@geekmidas/client 9.0.2 → 10.0.0-alpha.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.
Files changed (81) hide show
  1. package/dist/auth-fetcher-CBYuL6rx.d.cts +158 -0
  2. package/dist/auth-fetcher-CBYuL6rx.d.cts.map +1 -0
  3. package/dist/auth-fetcher-DOj0iz21.mjs +77 -0
  4. package/dist/auth-fetcher-DOj0iz21.mjs.map +1 -0
  5. package/dist/auth-fetcher-DxS8zOLc.d.mts +158 -0
  6. package/dist/auth-fetcher-DxS8zOLc.d.mts.map +1 -0
  7. package/dist/auth-fetcher-HILABmws.cjs +82 -0
  8. package/dist/auth-fetcher-HILABmws.cjs.map +1 -0
  9. package/dist/auth-fetcher.cjs +3 -76
  10. package/dist/auth-fetcher.d.cts +3 -158
  11. package/dist/auth-fetcher.d.mts +3 -158
  12. package/dist/auth-fetcher.mjs +3 -76
  13. package/dist/endpoint-hooks.d.mts +1 -1
  14. package/dist/fetcher-C1xtCKpT.d.mts +25 -0
  15. package/dist/fetcher-C1xtCKpT.d.mts.map +1 -0
  16. package/dist/fetcher-cDrfwN-Y.d.cts +25 -0
  17. package/dist/fetcher-cDrfwN-Y.d.cts.map +1 -0
  18. package/dist/fetcher.d.cts +3 -25
  19. package/dist/fetcher.d.mts +3 -25
  20. package/dist/index.cjs +8 -0
  21. package/dist/index.d.cts +5 -0
  22. package/dist/index.d.mts +5 -0
  23. package/dist/index.mjs +6 -0
  24. package/dist/infer-6KKCgmg1.cjs +0 -0
  25. package/{src/infer.ts → dist/infer-DfRq5kIb.d.cts} +54 -83
  26. package/dist/infer-DfRq5kIb.d.cts.map +1 -0
  27. package/dist/infer-bTirNeNW.d.mts +133 -0
  28. package/dist/infer-bTirNeNW.d.mts.map +1 -0
  29. package/dist/infer-uCUq1whM.mjs +0 -0
  30. package/dist/infer.cjs +1 -0
  31. package/dist/infer.d.cts +2 -133
  32. package/dist/infer.d.mts +2 -133
  33. package/dist/infer.mjs +1 -0
  34. package/dist/openapi-hooks.cjs.map +1 -1
  35. package/dist/openapi-hooks.d.cts +3 -3
  36. package/dist/openapi-hooks.d.cts.map +1 -1
  37. package/dist/openapi-hooks.d.mts +1 -1
  38. package/dist/openapi-hooks.d.mts.map +1 -1
  39. package/dist/openapi-hooks.mjs.map +1 -1
  40. package/dist/react-query.d.cts +7 -7
  41. package/dist/react-query.d.mts +1 -1
  42. package/dist/types-BH8WgGrm.mjs +0 -0
  43. package/dist/{types-D8Jrl4o3.d.mts → types-BMGM6sZc.d.mts} +1 -1
  44. package/dist/{types-D8Jrl4o3.d.mts.map → types-BMGM6sZc.d.mts.map} +1 -1
  45. package/dist/types-a8gm_IaQ.cjs +0 -0
  46. package/dist/types.cjs +1 -0
  47. package/dist/types.d.mts +1 -1
  48. package/dist/types.mjs +1 -0
  49. package/package.json +8 -5
  50. package/CHANGELOG.md +0 -146
  51. package/dist/auth-fetcher.cjs.map +0 -1
  52. package/dist/auth-fetcher.d.cts.map +0 -1
  53. package/dist/auth-fetcher.d.mts.map +0 -1
  54. package/dist/auth-fetcher.mjs.map +0 -1
  55. package/dist/fetcher.d.cts.map +0 -1
  56. package/dist/fetcher.d.mts.map +0 -1
  57. package/dist/infer.d.cts.map +0 -1
  58. package/dist/infer.d.mts.map +0 -1
  59. package/src/__tests__/auth-fetcher.spec.ts +0 -505
  60. package/src/__tests__/endpoint-hooks.spec.tsx +0 -374
  61. package/src/__tests__/fetcher.spec.ts +0 -580
  62. package/src/__tests__/infer.integration.spec.ts +0 -188
  63. package/src/__tests__/infer.spec.ts +0 -189
  64. package/src/__tests__/method-restrictions.spec.tsx +0 -227
  65. package/src/__tests__/mutation-inference.spec.tsx +0 -343
  66. package/src/__tests__/openapi-hooks.spec.tsx +0 -557
  67. package/src/__tests__/react-query-infinite.spec.tsx +0 -1003
  68. package/src/__tests__/react-query-invalidation.spec.tsx +0 -239
  69. package/src/__tests__/react-query.spec.tsx +0 -582
  70. package/src/__tests__/setup.ts +0 -281
  71. package/src/__tests__/types.spec.ts +0 -134
  72. package/src/__tests__/url-parsing.spec.ts +0 -196
  73. package/src/auth-fetcher.ts +0 -288
  74. package/src/endpoint-hooks.ts +0 -346
  75. package/src/fetcher.ts +0 -171
  76. package/src/openapi-hooks.ts +0 -193
  77. package/src/openapi-types.d.ts +0 -440
  78. package/src/openapi.json +0 -595
  79. package/src/react-query.ts +0 -341
  80. package/src/types.ts +0 -226
  81. package/tsconfig.json +0 -12
@@ -1,288 +0,0 @@
1
- import { TypedFetcher } from './fetcher';
2
- import type {
3
- ExtractEndpointResponse,
4
- FetcherOptions,
5
- FilteredRequestConfig,
6
- TypedApiFunction,
7
- TypedEndpoint,
8
- } from './types';
9
-
10
- export type { FetcherOptions } from './types';
11
-
12
- /**
13
- * Security scheme object matching OpenAPI 3.1 specification.
14
- */
15
- export interface SecuritySchemeObject {
16
- type: 'apiKey' | 'http' | 'mutualTLS' | 'oauth2' | 'openIdConnect';
17
- description?: string;
18
- name?: string;
19
- in?: 'query' | 'header' | 'cookie';
20
- scheme?: string;
21
- bearerFormat?: string;
22
- flows?: Record<string, unknown>;
23
- openIdConnectUrl?: string;
24
- [key: string]: unknown;
25
- }
26
-
27
- /**
28
- * Extract all non-null security scheme IDs that are actually used in the API.
29
- * This gives us the union of scheme names that endpoints require.
30
- */
31
- export type UsedSecuritySchemes<
32
- EndpointAuth extends Record<string, string | null>,
33
- > = NonNullable<EndpointAuth[keyof EndpointAuth]>;
34
-
35
- /**
36
- * Interface for token storage and retrieval.
37
- * Compatible with @geekmidas/auth TokenClient.
38
- */
39
- export interface TokenProvider {
40
- /**
41
- * Get a valid access token, refreshing if necessary.
42
- */
43
- getValidAccessToken(): Promise<string | null>;
44
-
45
- /**
46
- * Create Authorization headers from the current token.
47
- */
48
- createValidAuthHeaders(): Promise<Record<string, string>>;
49
- }
50
-
51
- /**
52
- * Interface for API key providers.
53
- */
54
- export interface ApiKeyProvider {
55
- /**
56
- * Get the API key value.
57
- */
58
- getApiKey(): Promise<string> | string;
59
- }
60
-
61
- /**
62
- * Interface for AWS SigV4 request signing.
63
- */
64
- export interface AwsSigner {
65
- /**
66
- * Sign a request with AWS SigV4.
67
- * @param url - The request URL
68
- * @param init - The request init object
69
- * @returns Headers to add to the request
70
- */
71
- sign(url: string, init: RequestInit): Promise<Record<string, string>>;
72
- }
73
-
74
- /**
75
- * Auth strategy configuration for a specific security scheme type.
76
- */
77
- export type AuthStrategy =
78
- | { type: 'bearer'; tokenProvider: TokenProvider }
79
- | { type: 'apiKey'; apiKeyProvider: ApiKeyProvider; headerName?: string }
80
- | { type: 'iam'; signer: AwsSigner }
81
- | { type: 'none' };
82
-
83
- /**
84
- * Options for creating an auth-aware fetcher.
85
- *
86
- * @template EndpointAuth - Map of endpoint strings to their auth scheme (or null for public)
87
- * @template SecuritySchemes - Available security scheme definitions
88
- */
89
- export interface AuthFetcherOptions<
90
- EndpointAuth extends Record<string, string | null>,
91
- SecuritySchemes extends Record<string, SecuritySchemeObject>,
92
- > extends Omit<FetcherOptions, 'onRequest'> {
93
- /**
94
- * Runtime map of endpoints to their required auth scheme.
95
- * Generated by `gkm openapi --ts`.
96
- */
97
- endpointAuth: EndpointAuth;
98
-
99
- /**
100
- * Security scheme definitions.
101
- * Generated by `gkm openapi --ts`.
102
- */
103
- securitySchemes: SecuritySchemes;
104
-
105
- /**
106
- * Auth strategies for security schemes that are actually used.
107
- * Only schemes referenced in endpointAuth are required.
108
- *
109
- * @example
110
- * ```typescript
111
- * // If endpointAuth has: { 'GET /users': 'jwt', 'POST /data': 'iam', 'GET /public': null }
112
- * // Then authStrategies must include strategies for 'jwt' and 'iam'
113
- * authStrategies: {
114
- * jwt: { type: 'bearer', tokenProvider },
115
- * iam: { type: 'iam', signer: awsSigner },
116
- * }
117
- * ```
118
- */
119
- authStrategies: Record<UsedSecuritySchemes<EndpointAuth>, AuthStrategy>;
120
-
121
- /**
122
- * Optional request interceptor (runs after auth headers are added).
123
- */
124
- onRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;
125
- }
126
-
127
- /**
128
- * Creates an auth-aware fetcher that automatically applies the correct
129
- * authentication based on the endpoint being called.
130
- *
131
- * @example
132
- * ```typescript
133
- * import { endpointAuth, securitySchemes, paths } from './openapi';
134
- * import { TokenClient } from '@geekmidas/auth/client';
135
- *
136
- * const tokenClient = new TokenClient({ ... });
137
- *
138
- * const api = createAuthAwareFetcher<paths>({
139
- * baseURL: 'https://api.example.com',
140
- * endpointAuth,
141
- * securitySchemes,
142
- * authStrategies: {
143
- * bearer: { type: 'bearer', tokenProvider: tokenClient },
144
- * iam: { type: 'iam', signer: awsSigner },
145
- * },
146
- * });
147
- *
148
- * // Bearer auth automatically applied
149
- * const user = await api('GET /users/{id}', { params: { id: '123' } });
150
- *
151
- * // IAM SigV4 auth automatically applied
152
- * const tenant = await api('POST /tenants', { body: { name: 'Acme' } });
153
- * ```
154
- */
155
- export function createAuthAwareFetcher<
156
- Paths,
157
- EndpointAuth extends Record<string, string | null> = Record<
158
- string,
159
- string | null
160
- >,
161
- SecuritySchemes extends Record<string, SecuritySchemeObject> = Record<
162
- string,
163
- SecuritySchemeObject
164
- >,
165
- >(
166
- options: AuthFetcherOptions<EndpointAuth, SecuritySchemes> & {
167
- baseURL: string;
168
- },
169
- ): TypedApiFunction<Paths> {
170
- const {
171
- endpointAuth,
172
- securitySchemes,
173
- authStrategies,
174
- onRequest: userOnRequest,
175
- ...fetcherOptions
176
- } = options;
177
-
178
- // Create base fetcher with user's onRequest if provided
179
- const baseFetcher = new TypedFetcher<Paths>({
180
- ...fetcherOptions,
181
- onRequest: userOnRequest,
182
- });
183
-
184
- const fetcher = async <T extends TypedEndpoint<Paths>>(
185
- endpoint: T,
186
- config?: FilteredRequestConfig<Paths, T>,
187
- ): Promise<ExtractEndpointResponse<Paths, T>> => {
188
- // Look up auth requirement for this endpoint
189
- const schemeName = endpointAuth[endpoint as keyof EndpointAuth] as
190
- | string
191
- | null;
192
-
193
- let authHeaders: Record<string, string> = {};
194
-
195
- if (schemeName) {
196
- const scheme = securitySchemes[schemeName as keyof SecuritySchemes];
197
- // Since authStrategies is now required to have all used schemes,
198
- // we can safely access it - TypeScript ensures the strategy exists
199
- const strategy =
200
- authStrategies[schemeName as UsedSecuritySchemes<EndpointAuth>];
201
-
202
- if (strategy && scheme) {
203
- authHeaders = await resolveAuthHeaders(strategy, scheme);
204
- }
205
- }
206
-
207
- // Merge auth headers with config headers
208
- const existingHeaders =
209
- config && 'headers' in config && config.headers
210
- ? (config.headers as Record<string, string>)
211
- : {};
212
-
213
- const mergedConfig = {
214
- ...config,
215
- headers: {
216
- ...authHeaders,
217
- ...existingHeaders,
218
- },
219
- } as unknown as FilteredRequestConfig<Paths, T>;
220
-
221
- return baseFetcher.request(endpoint, mergedConfig);
222
- };
223
-
224
- return fetcher as TypedApiFunction<Paths>;
225
- }
226
-
227
- /**
228
- * Resolves auth headers based on the strategy and scheme.
229
- */
230
- async function resolveAuthHeaders(
231
- strategy: AuthStrategy,
232
- scheme: SecuritySchemeObject,
233
- ): Promise<Record<string, string>> {
234
- switch (strategy.type) {
235
- case 'bearer': {
236
- return strategy.tokenProvider.createValidAuthHeaders();
237
- }
238
-
239
- case 'apiKey': {
240
- const apiKey = await strategy.apiKeyProvider.getApiKey();
241
- const headerName = strategy.headerName || scheme.name || 'X-API-Key';
242
-
243
- if (scheme.in === 'header' || !scheme.in) {
244
- return { [headerName]: apiKey };
245
- }
246
- // Note: query and cookie API keys are handled differently
247
- // For now, we only support header-based API keys
248
- return {};
249
- }
250
-
251
- case 'iam': {
252
- // IAM signing requires the full URL and request config
253
- // This is a simplified version - full implementation would need
254
- // access to the complete request
255
- // For now, return empty - the actual signing should be done
256
- // in a custom onRequest interceptor if needed
257
- return {};
258
- }
259
- default:
260
- return {};
261
- }
262
- }
263
-
264
- /**
265
- * Type helper to extract the security scheme ID from an endpoint.
266
- */
267
- export type GetEndpointAuth<
268
- EndpointAuth extends Record<string, string | null>,
269
- Endpoint extends keyof EndpointAuth,
270
- > = EndpointAuth[Endpoint];
271
-
272
- /**
273
- * Type helper to get all authenticated endpoints.
274
- */
275
- export type AuthenticatedEndpoints<
276
- EndpointAuth extends Record<string, string | null>,
277
- > = {
278
- [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? never : K;
279
- }[keyof EndpointAuth];
280
-
281
- /**
282
- * Type helper to get all public endpoints.
283
- */
284
- export type PublicEndpoints<
285
- EndpointAuth extends Record<string, string | null>,
286
- > = {
287
- [K in keyof EndpointAuth]: EndpointAuth[K] extends null ? K : never;
288
- }[keyof EndpointAuth];
@@ -1,346 +0,0 @@
1
- import type {
2
- QueryClient,
3
- QueryFunctionContext,
4
- UseInfiniteQueryOptions,
5
- UseInfiniteQueryResult,
6
- UseMutationOptions,
7
- UseMutationResult,
8
- UseQueryOptions,
9
- UseQueryResult,
10
- } from '@tanstack/react-query';
11
- import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query';
12
- import { useMemo } from 'react';
13
- import type {
14
- ExtractEndpointResponse,
15
- FilteredRequestConfig,
16
- IsConfigRequired,
17
- MutationEndpoint,
18
- QueryEndpoint,
19
- TypedApiFunction,
20
- } from './types';
21
-
22
- /**
23
- * Build query key from endpoint and config
24
- */
25
- function buildQueryKey<Paths, T extends QueryEndpoint<Paths>>(
26
- endpoint: T,
27
- config?: FilteredRequestConfig<Paths, T>,
28
- ): unknown[] {
29
- const key: unknown[] = [endpoint];
30
-
31
- if (config && 'params' in config && config.params) {
32
- key.push({ params: config.params });
33
- }
34
-
35
- if (config && 'query' in config && config.query) {
36
- key.push({ query: config.query });
37
- }
38
-
39
- return key;
40
- }
41
-
42
- /**
43
- * Options for creating endpoint-based hooks
44
- */
45
- export interface CreateEndpointHooksOptions {
46
- queryClient?: QueryClient;
47
- }
48
-
49
- /**
50
- * Hook options type that conditionally requires config
51
- */
52
- type UseQueryArgs<Paths, T extends QueryEndpoint<Paths>> = IsConfigRequired<
53
- Paths,
54
- T
55
- > extends true
56
- ? [
57
- config: FilteredRequestConfig<Paths, T>,
58
- options?: Omit<
59
- UseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,
60
- 'queryKey' | 'queryFn'
61
- >,
62
- ]
63
- : [
64
- config?: FilteredRequestConfig<Paths, T>,
65
- options?: Omit<
66
- UseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,
67
- 'queryKey' | 'queryFn'
68
- >,
69
- ];
70
-
71
- /**
72
- * Endpoint-based React Query hooks
73
- */
74
- export interface EndpointHooks<Paths> {
75
- /**
76
- * Use query hook for GET endpoints.
77
- * Config is required when endpoint has path params.
78
- */
79
- useQuery: <T extends QueryEndpoint<Paths>>(
80
- endpoint: T,
81
- ...args: UseQueryArgs<Paths, T>
82
- ) => UseQueryResult<ExtractEndpointResponse<Paths, T>, Error>;
83
-
84
- /**
85
- * Use mutation hook for POST, PUT, PATCH, DELETE endpoints.
86
- * Config with params/body is passed to mutate().
87
- */
88
- useMutation: <T extends MutationEndpoint<Paths>>(
89
- endpoint: T,
90
- options?: Omit<
91
- UseMutationOptions<
92
- ExtractEndpointResponse<Paths, T>,
93
- Error,
94
- FilteredRequestConfig<Paths, T>
95
- >,
96
- 'mutationFn'
97
- >,
98
- ) => UseMutationResult<
99
- ExtractEndpointResponse<Paths, T>,
100
- Error,
101
- FilteredRequestConfig<Paths, T>
102
- >;
103
-
104
- /**
105
- * Use infinite query hook for paginated GET endpoints.
106
- */
107
- useInfiniteQuery: <
108
- T extends QueryEndpoint<Paths>,
109
- TPageData = ExtractEndpointResponse<Paths, T>,
110
- TPageParam = unknown,
111
- >(
112
- endpoint: T,
113
- options: Omit<
114
- UseInfiniteQueryOptions<
115
- TPageData,
116
- Error,
117
- { pages: TPageData[]; pageParams: TPageParam[] },
118
- unknown[],
119
- TPageParam
120
- >,
121
- 'queryKey' | 'queryFn' | 'getNextPageParam' | 'initialPageParam'
122
- > & {
123
- getNextPageParam: (
124
- lastPage: TPageData,
125
- allPages: TPageData[],
126
- lastPageParam: TPageParam,
127
- allPageParams: TPageParam[],
128
- ) => TPageParam | undefined;
129
- initialPageParam: TPageParam;
130
- },
131
- config?: FilteredRequestConfig<Paths, T>,
132
- ) => UseInfiniteQueryResult<
133
- { pages: TPageData[]; pageParams: TPageParam[] },
134
- Error
135
- >;
136
-
137
- /**
138
- * Invalidate queries for a specific endpoint.
139
- */
140
- invalidateQueries: <T extends QueryEndpoint<Paths>>(
141
- endpoint: T,
142
- config?: FilteredRequestConfig<Paths, T>,
143
- ) => Promise<void>;
144
-
145
- /**
146
- * Invalidate all queries in the cache.
147
- */
148
- invalidateAllQueries: () => Promise<void>;
149
-
150
- /**
151
- * Build a query key for manual cache operations
152
- */
153
- buildQueryKey: <T extends QueryEndpoint<Paths>>(
154
- endpoint: T,
155
- config?: FilteredRequestConfig<Paths, T>,
156
- ) => unknown[];
157
- }
158
-
159
- /**
160
- * Create endpoint-based React Query hooks from a typed fetcher.
161
- *
162
- * @example
163
- * ```typescript
164
- * const fetcher = createAuthAwareFetcher<paths>({ ... });
165
- * const hooks = createEndpointHooks<paths>(fetcher);
166
- *
167
- * // In a component
168
- * const { data } = hooks.useQuery('GET /users/{id}', { params: { id: '123' } });
169
- *
170
- * const mutation = hooks.useMutation('POST /users');
171
- * await mutation.mutateAsync({ body: { name: 'John' } });
172
- * ```
173
- */
174
- export function createEndpointHooks<Paths>(
175
- fetcher: TypedApiFunction<Paths>,
176
- options: CreateEndpointHooksOptions = {},
177
- ): EndpointHooks<Paths> {
178
- return {
179
- useQuery: <T extends QueryEndpoint<Paths>>(
180
- endpoint: T,
181
- ...args: UseQueryArgs<Paths, T>
182
- ) => {
183
- // Parse args - config is first, options is second
184
- const [config, queryOptions] = args as [
185
- FilteredRequestConfig<Paths, T> | undefined,
186
- (
187
- | Omit<
188
- UseQueryOptions<ExtractEndpointResponse<Paths, T>, Error>,
189
- 'queryKey' | 'queryFn'
190
- >
191
- | undefined
192
- ),
193
- ];
194
-
195
- const queryKey = buildQueryKey(endpoint, config);
196
-
197
- const memoizedOptions = useMemo(
198
- () => ({
199
- queryKey,
200
- queryFn: () =>
201
- // Type assertion needed due to complex conditional types
202
- (
203
- fetcher as (
204
- endpoint: T,
205
- config?: unknown,
206
- ) => Promise<ExtractEndpointResponse<Paths, T>>
207
- )(endpoint, config),
208
- ...queryOptions,
209
- }),
210
- [endpoint, config, fetcher, queryKey, queryOptions],
211
- );
212
-
213
- return useQuery<ExtractEndpointResponse<Paths, T>, Error>(
214
- memoizedOptions,
215
- );
216
- },
217
-
218
- useMutation: <T extends MutationEndpoint<Paths>>(
219
- endpoint: T,
220
- mutationOptions?: Omit<
221
- UseMutationOptions<
222
- ExtractEndpointResponse<Paths, T>,
223
- Error,
224
- FilteredRequestConfig<Paths, T>
225
- >,
226
- 'mutationFn'
227
- >,
228
- ) => {
229
- const memoizedOptions = useMemo(
230
- () => ({
231
- mutationFn: (config: FilteredRequestConfig<Paths, T>) =>
232
- // Type assertion needed due to complex conditional types
233
- (
234
- fetcher as (
235
- endpoint: T,
236
- config?: unknown,
237
- ) => Promise<ExtractEndpointResponse<Paths, T>>
238
- )(endpoint, config),
239
- ...mutationOptions,
240
- }),
241
- [endpoint, fetcher, mutationOptions],
242
- );
243
-
244
- return useMutation<
245
- ExtractEndpointResponse<Paths, T>,
246
- Error,
247
- FilteredRequestConfig<Paths, T>
248
- >(memoizedOptions);
249
- },
250
-
251
- useInfiniteQuery: <
252
- T extends QueryEndpoint<Paths>,
253
- TPageData = ExtractEndpointResponse<Paths, T>,
254
- TPageParam = unknown,
255
- >(
256
- endpoint: T,
257
- options: Omit<
258
- UseInfiniteQueryOptions<
259
- TPageData,
260
- Error,
261
- { pages: TPageData[]; pageParams: TPageParam[] },
262
- unknown[],
263
- TPageParam
264
- >,
265
- 'queryKey' | 'queryFn' | 'getNextPageParam' | 'initialPageParam'
266
- > & {
267
- getNextPageParam: (
268
- lastPage: TPageData,
269
- allPages: TPageData[],
270
- lastPageParam: TPageParam,
271
- allPageParams: TPageParam[],
272
- ) => TPageParam | undefined;
273
- initialPageParam: TPageParam;
274
- },
275
- config?: FilteredRequestConfig<Paths, T>,
276
- ) => {
277
- const queryKey = buildQueryKey(endpoint, config);
278
-
279
- const memoizedOptions = useMemo(
280
- () => ({
281
- queryKey,
282
- queryFn: ({
283
- pageParam,
284
- }: QueryFunctionContext<unknown[], TPageParam>) => {
285
- let mergedConfig = config;
286
- if (pageParam !== undefined && config) {
287
- const pageQuery =
288
- typeof pageParam === 'object' ? pageParam : { page: pageParam };
289
- mergedConfig = {
290
- ...config,
291
- query: { ...(config as any).query, ...pageQuery },
292
- } as any;
293
- } else if (pageParam !== undefined && !config) {
294
- const pageQuery =
295
- typeof pageParam === 'object' ? pageParam : { page: pageParam };
296
- mergedConfig = { query: pageQuery } as any;
297
- }
298
- return (
299
- fetcher as (
300
- endpoint: T,
301
- config?: unknown,
302
- ) => Promise<ExtractEndpointResponse<Paths, T>>
303
- )(endpoint, mergedConfig) as Promise<TPageData>;
304
- },
305
- ...options,
306
- }),
307
- [endpoint, config, fetcher, queryKey, options],
308
- );
309
-
310
- return useInfiniteQuery<
311
- TPageData,
312
- Error,
313
- { pages: TPageData[]; pageParams: TPageParam[] },
314
- unknown[],
315
- TPageParam
316
- >(memoizedOptions);
317
- },
318
-
319
- invalidateQueries: <T extends QueryEndpoint<Paths>>(
320
- endpoint: T,
321
- config?: FilteredRequestConfig<Paths, T>,
322
- ) => {
323
- if (!options.queryClient) {
324
- throw new Error(
325
- 'queryClient is required for invalidateQueries. Pass it to createEndpointHooks options.',
326
- );
327
- }
328
- const queryKey = buildQueryKey(endpoint, config);
329
- return options.queryClient.invalidateQueries({
330
- queryKey,
331
- exact: !!config,
332
- });
333
- },
334
-
335
- invalidateAllQueries: () => {
336
- if (!options.queryClient) {
337
- throw new Error(
338
- 'queryClient is required for invalidateAllQueries. Pass it to createEndpointHooks options.',
339
- );
340
- }
341
- return options.queryClient.invalidateQueries();
342
- },
343
-
344
- buildQueryKey,
345
- };
346
- }