@geekmidas/client 9.0.1 → 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.
- package/dist/auth-fetcher-CBYuL6rx.d.cts +158 -0
- package/dist/auth-fetcher-CBYuL6rx.d.cts.map +1 -0
- package/dist/auth-fetcher-DOj0iz21.mjs +77 -0
- package/dist/auth-fetcher-DOj0iz21.mjs.map +1 -0
- package/dist/auth-fetcher-DxS8zOLc.d.mts +158 -0
- package/dist/auth-fetcher-DxS8zOLc.d.mts.map +1 -0
- package/dist/auth-fetcher-HILABmws.cjs +82 -0
- package/dist/auth-fetcher-HILABmws.cjs.map +1 -0
- package/dist/auth-fetcher.cjs +3 -76
- package/dist/auth-fetcher.d.cts +3 -158
- package/dist/auth-fetcher.d.mts +3 -158
- package/dist/auth-fetcher.mjs +3 -76
- package/dist/endpoint-hooks.d.mts +1 -1
- package/dist/fetcher-C1xtCKpT.d.mts +25 -0
- package/dist/fetcher-C1xtCKpT.d.mts.map +1 -0
- package/dist/fetcher-cDrfwN-Y.d.cts +25 -0
- package/dist/fetcher-cDrfwN-Y.d.cts.map +1 -0
- package/dist/fetcher.d.cts +3 -25
- package/dist/fetcher.d.mts +3 -25
- package/dist/index.cjs +8 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +6 -0
- package/dist/infer-6KKCgmg1.cjs +0 -0
- package/{src/infer.ts → dist/infer-DfRq5kIb.d.cts} +54 -83
- package/dist/infer-DfRq5kIb.d.cts.map +1 -0
- package/dist/infer-bTirNeNW.d.mts +133 -0
- package/dist/infer-bTirNeNW.d.mts.map +1 -0
- package/dist/infer-uCUq1whM.mjs +0 -0
- package/dist/infer.cjs +1 -0
- package/dist/infer.d.cts +2 -133
- package/dist/infer.d.mts +2 -133
- package/dist/infer.mjs +1 -0
- package/dist/openapi-hooks.cjs.map +1 -1
- package/dist/openapi-hooks.d.cts +3 -3
- package/dist/openapi-hooks.d.cts.map +1 -1
- package/dist/openapi-hooks.d.mts +1 -1
- package/dist/openapi-hooks.d.mts.map +1 -1
- package/dist/openapi-hooks.mjs.map +1 -1
- package/dist/react-query.d.cts +7 -7
- package/dist/react-query.d.mts +1 -1
- package/dist/types-BH8WgGrm.mjs +0 -0
- package/dist/{types-D8Jrl4o3.d.mts → types-BMGM6sZc.d.mts} +1 -1
- package/dist/{types-D8Jrl4o3.d.mts.map → types-BMGM6sZc.d.mts.map} +1 -1
- package/dist/types-a8gm_IaQ.cjs +0 -0
- package/dist/types.cjs +1 -0
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +1 -0
- package/package.json +8 -5
- package/CHANGELOG.md +0 -124
- package/dist/auth-fetcher.cjs.map +0 -1
- package/dist/auth-fetcher.d.cts.map +0 -1
- package/dist/auth-fetcher.d.mts.map +0 -1
- package/dist/auth-fetcher.mjs.map +0 -1
- package/dist/fetcher.d.cts.map +0 -1
- package/dist/fetcher.d.mts.map +0 -1
- package/dist/infer.d.cts.map +0 -1
- package/dist/infer.d.mts.map +0 -1
- package/src/__tests__/auth-fetcher.spec.ts +0 -505
- package/src/__tests__/endpoint-hooks.spec.tsx +0 -374
- package/src/__tests__/fetcher.spec.ts +0 -580
- package/src/__tests__/infer.integration.spec.ts +0 -188
- package/src/__tests__/infer.spec.ts +0 -189
- package/src/__tests__/method-restrictions.spec.tsx +0 -227
- package/src/__tests__/mutation-inference.spec.tsx +0 -343
- package/src/__tests__/openapi-hooks.spec.tsx +0 -557
- package/src/__tests__/react-query-infinite.spec.tsx +0 -1003
- package/src/__tests__/react-query-invalidation.spec.tsx +0 -239
- package/src/__tests__/react-query.spec.tsx +0 -582
- package/src/__tests__/setup.ts +0 -281
- package/src/__tests__/types.spec.ts +0 -134
- package/src/__tests__/url-parsing.spec.ts +0 -196
- package/src/auth-fetcher.ts +0 -288
- package/src/endpoint-hooks.ts +0 -346
- package/src/fetcher.ts +0 -171
- package/src/openapi-hooks.ts +0 -193
- package/src/openapi-types.d.ts +0 -440
- package/src/openapi.json +0 -595
- package/src/react-query.ts +0 -341
- package/src/types.ts +0 -226
- package/tsconfig.json +0 -12
package/src/react-query.ts
DELETED
|
@@ -1,341 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
QueryClient,
|
|
3
|
-
QueryFunctionContext,
|
|
4
|
-
UseInfiniteQueryOptions,
|
|
5
|
-
UseMutationOptions,
|
|
6
|
-
UseQueryOptions,
|
|
7
|
-
} from '@tanstack/react-query';
|
|
8
|
-
import {
|
|
9
|
-
useInfiniteQuery,
|
|
10
|
-
useMutation,
|
|
11
|
-
useQuery,
|
|
12
|
-
useQueryClient,
|
|
13
|
-
} from '@tanstack/react-query';
|
|
14
|
-
import { useMemo } from 'react';
|
|
15
|
-
import { createTypedFetcher } from './fetcher';
|
|
16
|
-
import type {
|
|
17
|
-
ExtractEndpointResponse,
|
|
18
|
-
FetcherOptions,
|
|
19
|
-
FilteredRequestConfig,
|
|
20
|
-
MutationEndpoint,
|
|
21
|
-
QueryEndpoint,
|
|
22
|
-
TypedEndpoint,
|
|
23
|
-
} from './types';
|
|
24
|
-
|
|
25
|
-
export interface TypedQueryClientOptions extends FetcherOptions {
|
|
26
|
-
queryClient?: QueryClient;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export class TypedQueryClient<Paths> {
|
|
30
|
-
private fetcher: ReturnType<typeof createTypedFetcher<Paths>>;
|
|
31
|
-
private queryClient?: QueryClient;
|
|
32
|
-
|
|
33
|
-
constructor(options: TypedQueryClientOptions = {}) {
|
|
34
|
-
this.fetcher = createTypedFetcher<Paths>(options);
|
|
35
|
-
this.queryClient = options.queryClient;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
useQuery<T extends QueryEndpoint<Paths>>(
|
|
39
|
-
endpoint: T,
|
|
40
|
-
config?: FilteredRequestConfig<Paths, T>,
|
|
41
|
-
options?: Omit<
|
|
42
|
-
UseQueryOptions<ExtractEndpointResponse<Paths, T>, Response>,
|
|
43
|
-
'queryKey' | 'queryFn'
|
|
44
|
-
>,
|
|
45
|
-
) {
|
|
46
|
-
const queryKey = this.buildQueryKey(endpoint, config);
|
|
47
|
-
|
|
48
|
-
// Memoize the combined options to prevent unnecessary re-renders
|
|
49
|
-
const memoizedOptions = useMemo(
|
|
50
|
-
() => ({
|
|
51
|
-
queryKey,
|
|
52
|
-
queryFn: () => this.fetcher(endpoint, config),
|
|
53
|
-
...options,
|
|
54
|
-
}),
|
|
55
|
-
// Dependencies: queryKey, endpoint, config, and options
|
|
56
|
-
// Note: We stringify config and options to ensure stable references
|
|
57
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
58
|
-
[
|
|
59
|
-
queryKey.join(','),
|
|
60
|
-
endpoint,
|
|
61
|
-
JSON.stringify(config),
|
|
62
|
-
JSON.stringify(options),
|
|
63
|
-
],
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
return useQuery<ExtractEndpointResponse<Paths, T>, Response>(
|
|
67
|
-
memoizedOptions,
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
useMutation<T extends MutationEndpoint<Paths>>(
|
|
72
|
-
endpoint: T,
|
|
73
|
-
options?: Omit<
|
|
74
|
-
UseMutationOptions<
|
|
75
|
-
ExtractEndpointResponse<Paths, T>,
|
|
76
|
-
Response,
|
|
77
|
-
FilteredRequestConfig<Paths, T>
|
|
78
|
-
>,
|
|
79
|
-
'mutationFn'
|
|
80
|
-
>,
|
|
81
|
-
) {
|
|
82
|
-
// Memoize the combined options to prevent unnecessary re-renders
|
|
83
|
-
const memoizedOptions = useMemo(
|
|
84
|
-
() => ({
|
|
85
|
-
mutationFn: (config: FilteredRequestConfig<Paths, T>) =>
|
|
86
|
-
this.fetcher(endpoint, config),
|
|
87
|
-
...options,
|
|
88
|
-
}),
|
|
89
|
-
// Dependencies: endpoint and options
|
|
90
|
-
// Note: We stringify options to ensure stable reference
|
|
91
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
92
|
-
[endpoint, JSON.stringify(options)],
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
return useMutation<
|
|
96
|
-
ExtractEndpointResponse<Paths, T>,
|
|
97
|
-
Response,
|
|
98
|
-
FilteredRequestConfig<Paths, T>
|
|
99
|
-
>(memoizedOptions);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
useInfiniteQuery<
|
|
103
|
-
T extends QueryEndpoint<Paths>,
|
|
104
|
-
TPageData = ExtractEndpointResponse<Paths, T>,
|
|
105
|
-
TPageParam = unknown,
|
|
106
|
-
>(
|
|
107
|
-
endpoint: T,
|
|
108
|
-
options: Omit<
|
|
109
|
-
UseInfiniteQueryOptions<
|
|
110
|
-
TPageData,
|
|
111
|
-
Response,
|
|
112
|
-
{ pages: TPageData[]; pageParams: TPageParam[] },
|
|
113
|
-
unknown[],
|
|
114
|
-
TPageParam
|
|
115
|
-
>,
|
|
116
|
-
'queryKey' | 'queryFn' | 'getNextPageParam' | 'initialPageParam'
|
|
117
|
-
> & {
|
|
118
|
-
getNextPageParam: (
|
|
119
|
-
lastPage: TPageData,
|
|
120
|
-
allPages: TPageData[],
|
|
121
|
-
lastPageParam: TPageParam,
|
|
122
|
-
allPageParams: TPageParam[],
|
|
123
|
-
) => TPageParam | undefined;
|
|
124
|
-
initialPageParam: TPageParam;
|
|
125
|
-
},
|
|
126
|
-
config?: FilteredRequestConfig<Paths, T>,
|
|
127
|
-
) {
|
|
128
|
-
const queryKey = this.buildQueryKey(endpoint, config);
|
|
129
|
-
|
|
130
|
-
// Memoize the combined options to prevent unnecessary re-renders
|
|
131
|
-
const memoizedOptions = useMemo(
|
|
132
|
-
() => ({
|
|
133
|
-
queryKey,
|
|
134
|
-
queryFn: ({
|
|
135
|
-
pageParam,
|
|
136
|
-
}: QueryFunctionContext<unknown[], TPageParam>) => {
|
|
137
|
-
let mergedConfig = config;
|
|
138
|
-
if (pageParam !== undefined && config) {
|
|
139
|
-
// If pageParam is an object, spread it into query
|
|
140
|
-
const pageQuery =
|
|
141
|
-
typeof pageParam === 'object' ? pageParam : { page: pageParam };
|
|
142
|
-
mergedConfig = {
|
|
143
|
-
...config,
|
|
144
|
-
query: { ...(config as any).query, ...pageQuery },
|
|
145
|
-
} as any;
|
|
146
|
-
} else if (pageParam !== undefined && !config) {
|
|
147
|
-
// If pageParam is an object, use it directly, otherwise wrap in page property
|
|
148
|
-
const pageQuery =
|
|
149
|
-
typeof pageParam === 'object' ? pageParam : { page: pageParam };
|
|
150
|
-
mergedConfig = { query: pageQuery } as any;
|
|
151
|
-
}
|
|
152
|
-
return this.fetcher(endpoint, mergedConfig) as Promise<TPageData>;
|
|
153
|
-
},
|
|
154
|
-
...options,
|
|
155
|
-
}),
|
|
156
|
-
// Dependencies: queryKey, endpoint, config, and options
|
|
157
|
-
// Note: We stringify config and options to ensure stable references
|
|
158
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
159
|
-
[
|
|
160
|
-
queryKey.join(','),
|
|
161
|
-
endpoint,
|
|
162
|
-
JSON.stringify(config),
|
|
163
|
-
JSON.stringify(options),
|
|
164
|
-
],
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
return useInfiniteQuery<
|
|
168
|
-
TPageData,
|
|
169
|
-
Response,
|
|
170
|
-
{ pages: TPageData[]; pageParams: TPageParam[] },
|
|
171
|
-
unknown[],
|
|
172
|
-
TPageParam
|
|
173
|
-
>(memoizedOptions);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
buildQueryKey<T extends TypedEndpoint<Paths>>(
|
|
177
|
-
endpoint: T,
|
|
178
|
-
config?: FilteredRequestConfig<Paths, T>,
|
|
179
|
-
): unknown[] {
|
|
180
|
-
const key: unknown[] = [endpoint];
|
|
181
|
-
|
|
182
|
-
if (config && 'params' in config && config.params) {
|
|
183
|
-
key.push({ params: config.params });
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (config && 'query' in config && config.query) {
|
|
187
|
-
key.push({ query: config.query });
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return key;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Invalidate queries for a specific endpoint with optional config
|
|
195
|
-
* @param endpoint - The endpoint to invalidate (e.g., 'GET /users')
|
|
196
|
-
* @param config - Optional params/query to match specific queries
|
|
197
|
-
* @returns Promise that resolves when invalidation is complete
|
|
198
|
-
*/
|
|
199
|
-
invalidateQueries<T extends QueryEndpoint<Paths>>(
|
|
200
|
-
endpoint: T,
|
|
201
|
-
config?: FilteredRequestConfig<Paths, T>,
|
|
202
|
-
): Promise<void> {
|
|
203
|
-
const queryClient = this.getQueryClient();
|
|
204
|
-
const queryKey = this.buildQueryKey(endpoint, config);
|
|
205
|
-
|
|
206
|
-
return queryClient.invalidateQueries({
|
|
207
|
-
queryKey,
|
|
208
|
-
exact: !!config, // Use exact matching if config is provided
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Invalidate all queries in the cache
|
|
214
|
-
* @returns Promise that resolves when invalidation is complete
|
|
215
|
-
*/
|
|
216
|
-
invalidateAllQueries(): Promise<void> {
|
|
217
|
-
const queryClient = this.getQueryClient();
|
|
218
|
-
return queryClient.invalidateQueries();
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Get the underlying QueryClient instance
|
|
223
|
-
* @returns The QueryClient instance
|
|
224
|
-
*/
|
|
225
|
-
getQueryClient(): QueryClient {
|
|
226
|
-
if (this.queryClient) {
|
|
227
|
-
return this.queryClient;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// If no query client was provided, try to get it from context
|
|
231
|
-
// This will throw if used outside of QueryClientProvider
|
|
232
|
-
throw new Error(
|
|
233
|
-
'No QueryClient set, please provide a QueryClient via the queryClient option or ensure you are within a QueryClientProvider',
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Set the QueryClient instance
|
|
239
|
-
* @param queryClient - The QueryClient instance to use
|
|
240
|
-
*/
|
|
241
|
-
setQueryClient(queryClient: QueryClient): void {
|
|
242
|
-
this.queryClient = queryClient;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export function createTypedQueryClient<Paths>(
|
|
247
|
-
options?: TypedQueryClientOptions,
|
|
248
|
-
) {
|
|
249
|
-
return new TypedQueryClient<Paths>(options);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Hook exports for convenience
|
|
253
|
-
export function useTypedQuery<Paths, T extends QueryEndpoint<Paths>>(
|
|
254
|
-
client: TypedQueryClient<Paths>,
|
|
255
|
-
endpoint: T,
|
|
256
|
-
config?: FilteredRequestConfig<Paths, T>,
|
|
257
|
-
options?: Omit<
|
|
258
|
-
UseQueryOptions<ExtractEndpointResponse<Paths, T>, Response>,
|
|
259
|
-
'queryKey' | 'queryFn'
|
|
260
|
-
>,
|
|
261
|
-
) {
|
|
262
|
-
return client.useQuery(endpoint, config, options);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
export function useTypedMutation<Paths, T extends MutationEndpoint<Paths>>(
|
|
266
|
-
client: TypedQueryClient<Paths>,
|
|
267
|
-
endpoint: T,
|
|
268
|
-
options?: Omit<
|
|
269
|
-
UseMutationOptions<
|
|
270
|
-
ExtractEndpointResponse<Paths, T>,
|
|
271
|
-
Response,
|
|
272
|
-
FilteredRequestConfig<Paths, T>
|
|
273
|
-
>,
|
|
274
|
-
'mutationFn'
|
|
275
|
-
>,
|
|
276
|
-
) {
|
|
277
|
-
return client.useMutation(endpoint, options);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
export function useTypedInfiniteQuery<
|
|
281
|
-
Paths,
|
|
282
|
-
T extends QueryEndpoint<Paths>,
|
|
283
|
-
TPageData = ExtractEndpointResponse<Paths, T>,
|
|
284
|
-
TPageParam = unknown,
|
|
285
|
-
>(
|
|
286
|
-
client: TypedQueryClient<Paths>,
|
|
287
|
-
endpoint: T,
|
|
288
|
-
options: Omit<
|
|
289
|
-
UseInfiniteQueryOptions<
|
|
290
|
-
TPageData,
|
|
291
|
-
Response,
|
|
292
|
-
{ pages: TPageData[]; pageParams: TPageParam[] },
|
|
293
|
-
unknown[],
|
|
294
|
-
TPageParam
|
|
295
|
-
>,
|
|
296
|
-
'queryKey' | 'queryFn' | 'getNextPageParam' | 'initialPageParam'
|
|
297
|
-
> & {
|
|
298
|
-
getNextPageParam: (
|
|
299
|
-
lastPage: TPageData,
|
|
300
|
-
allPages: TPageData[],
|
|
301
|
-
lastPageParam: TPageParam,
|
|
302
|
-
allPageParams: TPageParam[],
|
|
303
|
-
) => TPageParam | undefined;
|
|
304
|
-
initialPageParam: TPageParam;
|
|
305
|
-
},
|
|
306
|
-
config?: FilteredRequestConfig<Paths, T>,
|
|
307
|
-
) {
|
|
308
|
-
return client.useInfiniteQuery(endpoint, options, config);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Hook to invalidate queries using the current QueryClient from context
|
|
313
|
-
*/
|
|
314
|
-
export function useTypedInvalidateQueries<Paths>(
|
|
315
|
-
client: TypedQueryClient<Paths>,
|
|
316
|
-
) {
|
|
317
|
-
const queryClient = useQueryClient();
|
|
318
|
-
|
|
319
|
-
return {
|
|
320
|
-
/**
|
|
321
|
-
* Invalidate queries for a specific endpoint
|
|
322
|
-
*/
|
|
323
|
-
invalidateQueries: <T extends QueryEndpoint<Paths>>(
|
|
324
|
-
endpoint: T,
|
|
325
|
-
config?: FilteredRequestConfig<Paths, T>,
|
|
326
|
-
) => {
|
|
327
|
-
const queryKey = client.buildQueryKey(endpoint, config);
|
|
328
|
-
return queryClient.invalidateQueries({
|
|
329
|
-
queryKey,
|
|
330
|
-
exact: !!config,
|
|
331
|
-
});
|
|
332
|
-
},
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Invalidate all queries
|
|
336
|
-
*/
|
|
337
|
-
invalidateAllQueries: () => {
|
|
338
|
-
return queryClient.invalidateQueries();
|
|
339
|
-
},
|
|
340
|
-
};
|
|
341
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
export type OpenAPIRoutes<Paths> = keyof Paths;
|
|
2
|
-
|
|
3
|
-
type HttpMethod =
|
|
4
|
-
| 'get'
|
|
5
|
-
| 'post'
|
|
6
|
-
| 'put'
|
|
7
|
-
| 'patch'
|
|
8
|
-
| 'delete'
|
|
9
|
-
| 'head'
|
|
10
|
-
| 'options';
|
|
11
|
-
|
|
12
|
-
export type ExtractMethod<Paths, Route extends OpenAPIRoutes<Paths>> = Extract<
|
|
13
|
-
keyof Paths[Route],
|
|
14
|
-
HttpMethod
|
|
15
|
-
>;
|
|
16
|
-
|
|
17
|
-
export type ExtractPathParams<
|
|
18
|
-
Paths,
|
|
19
|
-
Route extends OpenAPIRoutes<Paths>,
|
|
20
|
-
> = Paths[Route] extends {
|
|
21
|
-
parameters?: { path?: infer P };
|
|
22
|
-
}
|
|
23
|
-
? P
|
|
24
|
-
: never;
|
|
25
|
-
|
|
26
|
-
export type ExtractQueryParams<
|
|
27
|
-
Paths,
|
|
28
|
-
Route extends OpenAPIRoutes<Paths>,
|
|
29
|
-
Method extends ExtractMethod<Paths, Route>,
|
|
30
|
-
> = Paths[Route][Method] extends { parameters?: { query?: infer Q } }
|
|
31
|
-
? Q
|
|
32
|
-
: never;
|
|
33
|
-
|
|
34
|
-
export type ExtractRequestBody<
|
|
35
|
-
Paths,
|
|
36
|
-
Route extends OpenAPIRoutes<Paths>,
|
|
37
|
-
Method extends ExtractMethod<Paths, Route>,
|
|
38
|
-
> = Paths[Route][Method] extends {
|
|
39
|
-
requestBody?: { content?: { 'application/json'?: infer B } };
|
|
40
|
-
}
|
|
41
|
-
? B
|
|
42
|
-
: never;
|
|
43
|
-
|
|
44
|
-
export type ExtractResponse<
|
|
45
|
-
Paths,
|
|
46
|
-
Route extends OpenAPIRoutes<Paths>,
|
|
47
|
-
Method extends ExtractMethod<Paths, Route>,
|
|
48
|
-
> = Paths[Route][Method] extends {
|
|
49
|
-
responses?: { 200?: { content?: { 'application/json'?: infer R } } };
|
|
50
|
-
}
|
|
51
|
-
? R
|
|
52
|
-
: Paths[Route][Method] extends {
|
|
53
|
-
responses?: { 201?: { content?: { 'application/json'?: infer R } } };
|
|
54
|
-
}
|
|
55
|
-
? R
|
|
56
|
-
: never;
|
|
57
|
-
|
|
58
|
-
export type RequestConfig<
|
|
59
|
-
Paths,
|
|
60
|
-
Route extends OpenAPIRoutes<Paths>,
|
|
61
|
-
Method extends ExtractMethod<Paths, Route>,
|
|
62
|
-
> = {
|
|
63
|
-
params?: ExtractPathParams<Paths, Route>;
|
|
64
|
-
query?: ExtractQueryParams<Paths, Route, Method>;
|
|
65
|
-
body?: ExtractRequestBody<Paths, Route, Method>;
|
|
66
|
-
headers?: Record<string, string>;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export type EndpointString = `${Uppercase<string>} ${string}`;
|
|
70
|
-
|
|
71
|
-
// Generate all valid endpoint strings from OpenAPI paths
|
|
72
|
-
// Uses Extract with HttpMethod to filter out non-HTTP keys like 'parameters'
|
|
73
|
-
export type ValidEndpoint<Paths> = {
|
|
74
|
-
[Route in keyof Paths]: {
|
|
75
|
-
[Method in Extract<keyof Paths[Route], HttpMethod>]: `${Uppercase<
|
|
76
|
-
string & Method
|
|
77
|
-
>} ${string & Route}`;
|
|
78
|
-
}[Extract<keyof Paths[Route], HttpMethod>];
|
|
79
|
-
}[keyof Paths];
|
|
80
|
-
|
|
81
|
-
// Helper type to get autocomplete for endpoint strings
|
|
82
|
-
export type TypedEndpoint<Paths> =
|
|
83
|
-
ValidEndpoint<Paths> extends infer E ? (E extends string ? E : never) : never;
|
|
84
|
-
|
|
85
|
-
// Filter endpoints by HTTP method
|
|
86
|
-
export type FilterEndpointByMethod<
|
|
87
|
-
Paths,
|
|
88
|
-
Method extends string,
|
|
89
|
-
> = ValidEndpoint<Paths> extends infer E
|
|
90
|
-
? E extends `${Method} ${string}`
|
|
91
|
-
? E
|
|
92
|
-
: never
|
|
93
|
-
: never;
|
|
94
|
-
|
|
95
|
-
// Query endpoints (GET only)
|
|
96
|
-
export type QueryEndpoint<Paths> = FilterEndpointByMethod<Paths, 'GET'>;
|
|
97
|
-
|
|
98
|
-
// Mutation endpoints (POST, PATCH, PUT, DELETE)
|
|
99
|
-
export type MutationEndpoint<Paths> =
|
|
100
|
-
| FilterEndpointByMethod<Paths, 'POST'>
|
|
101
|
-
| FilterEndpointByMethod<Paths, 'PATCH'>
|
|
102
|
-
| FilterEndpointByMethod<Paths, 'PUT'>
|
|
103
|
-
| FilterEndpointByMethod<Paths, 'DELETE'>;
|
|
104
|
-
|
|
105
|
-
export type ParseEndpoint<T extends EndpointString> =
|
|
106
|
-
T extends `${infer Method} ${infer Route}`
|
|
107
|
-
? { method: Lowercase<Method>; route: Route }
|
|
108
|
-
: never;
|
|
109
|
-
|
|
110
|
-
export type ExtractEndpointResponse<
|
|
111
|
-
Paths,
|
|
112
|
-
T extends EndpointString,
|
|
113
|
-
> = T extends `${infer Method} ${infer Route}`
|
|
114
|
-
? Route extends OpenAPIRoutes<Paths>
|
|
115
|
-
? Lowercase<Method> extends ExtractMethod<Paths, Route>
|
|
116
|
-
? ExtractResponse<Paths, Route, Lowercase<Method>>
|
|
117
|
-
: never
|
|
118
|
-
: never
|
|
119
|
-
: never;
|
|
120
|
-
|
|
121
|
-
export type ExtractEndpointConfig<
|
|
122
|
-
Paths,
|
|
123
|
-
T extends EndpointString,
|
|
124
|
-
> = T extends `${infer Method} ${infer Route}`
|
|
125
|
-
? Route extends OpenAPIRoutes<Paths>
|
|
126
|
-
? Lowercase<Method> extends ExtractMethod<Paths, Route>
|
|
127
|
-
? RequestConfig<Paths, Route, Lowercase<Method>>
|
|
128
|
-
: never
|
|
129
|
-
: never
|
|
130
|
-
: never;
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Build a request config type where:
|
|
134
|
-
* - `params` is required if the endpoint has path parameters
|
|
135
|
-
* - `body` is required if the endpoint has a request body
|
|
136
|
-
* - `query` and `headers` are always optional
|
|
137
|
-
*/
|
|
138
|
-
export type FilteredRequestConfig<
|
|
139
|
-
Paths,
|
|
140
|
-
T extends EndpointString,
|
|
141
|
-
> = T extends `${infer Method} ${infer Route}`
|
|
142
|
-
? Route extends OpenAPIRoutes<Paths>
|
|
143
|
-
? Lowercase<Method> extends ExtractMethod<Paths, Route>
|
|
144
|
-
? BuildRequestConfig<
|
|
145
|
-
ExtractPathParams<Paths, Route>,
|
|
146
|
-
ExtractQueryParams<Paths, Route, Lowercase<Method>>,
|
|
147
|
-
ExtractRequestBody<Paths, Route, Lowercase<Method>>
|
|
148
|
-
>
|
|
149
|
-
: never
|
|
150
|
-
: never
|
|
151
|
-
: never;
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Helper to build request config with correct required/optional fields.
|
|
155
|
-
* Uses [T] extends [never] pattern to prevent distribution over union types,
|
|
156
|
-
* which would cause the entire type to become `never`.
|
|
157
|
-
*/
|
|
158
|
-
type BuildRequestConfig<TParams, TQuery, TBody> = SimplifyIntersection<
|
|
159
|
-
// params: required if not never
|
|
160
|
-
([TParams] extends [never] ? {} : { params: TParams }) &
|
|
161
|
-
// body: required if not never
|
|
162
|
-
([TBody] extends [never] ? {} : { body: TBody }) &
|
|
163
|
-
// query: optional if not never
|
|
164
|
-
([TQuery] extends [never] ? {} : { query?: TQuery }) & {
|
|
165
|
-
// headers: always optional
|
|
166
|
-
headers?: Record<string, string>;
|
|
167
|
-
}
|
|
168
|
-
>;
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Simplify intersection types for better IDE display
|
|
172
|
-
*/
|
|
173
|
-
type SimplifyIntersection<T> = { [K in keyof T]: T[K] };
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Check if the config object is required (has any required fields)
|
|
177
|
-
*/
|
|
178
|
-
export type IsConfigRequired<
|
|
179
|
-
Paths,
|
|
180
|
-
T extends EndpointString,
|
|
181
|
-
> = T extends `${infer Method} ${infer Route}`
|
|
182
|
-
? Route extends OpenAPIRoutes<Paths>
|
|
183
|
-
? Lowercase<Method> extends ExtractMethod<Paths, Route>
|
|
184
|
-
? ExtractPathParams<Paths, Route> extends never
|
|
185
|
-
? ExtractRequestBody<Paths, Route, Lowercase<Method>> extends never
|
|
186
|
-
? false
|
|
187
|
-
: true
|
|
188
|
-
: true
|
|
189
|
-
: false
|
|
190
|
-
: false
|
|
191
|
-
: false;
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Typed function signature for the API client.
|
|
195
|
-
* Config is required when endpoint has path params or body.
|
|
196
|
-
*/
|
|
197
|
-
export type TypedApiFunction<Paths> = <T extends TypedEndpoint<Paths>>(
|
|
198
|
-
endpoint: T,
|
|
199
|
-
...args: IsConfigRequired<Paths, T> extends true
|
|
200
|
-
? [config: FilteredRequestConfig<Paths, T>]
|
|
201
|
-
: [config?: FilteredRequestConfig<Paths, T>]
|
|
202
|
-
) => Promise<ExtractEndpointResponse<Paths, T>>;
|
|
203
|
-
|
|
204
|
-
export interface FetcherOptions {
|
|
205
|
-
baseURL?: string;
|
|
206
|
-
headers?: Record<string, string>;
|
|
207
|
-
onRequest?: (config: RequestInit) => RequestInit | Promise<RequestInit>;
|
|
208
|
-
onResponse?: (response: Response) => Response | Promise<Response>;
|
|
209
|
-
onError?: (error: Error) => void | Promise<void>;
|
|
210
|
-
fetch?: typeof fetch;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export type WrappedResult<T, E = unknown> =
|
|
214
|
-
| { ok: true; data: T }
|
|
215
|
-
| { ok: false; error: E };
|
|
216
|
-
|
|
217
|
-
export type ErrorTransformer<E> = (error: unknown) => E | Promise<E>;
|
|
218
|
-
|
|
219
|
-
export type WrappedApiFunction<Paths, E = unknown> = <
|
|
220
|
-
T extends TypedEndpoint<Paths>,
|
|
221
|
-
>(
|
|
222
|
-
endpoint: T,
|
|
223
|
-
...args: IsConfigRequired<Paths, T> extends true
|
|
224
|
-
? [config: FilteredRequestConfig<Paths, T>]
|
|
225
|
-
: [config?: FilteredRequestConfig<Paths, T>]
|
|
226
|
-
) => Promise<WrappedResult<ExtractEndpointResponse<Paths, T>, E>>;
|
package/tsconfig.json
DELETED