@geekmidas/client 0.3.0 → 0.5.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.cjs +2 -3
- package/dist/auth-fetcher.cjs.map +1 -1
- package/dist/auth-fetcher.d.cts +2 -1
- package/dist/auth-fetcher.d.cts.map +1 -0
- package/dist/auth-fetcher.d.mts +2 -1
- package/dist/auth-fetcher.d.mts.map +1 -0
- package/dist/auth-fetcher.mjs +2 -3
- package/dist/auth-fetcher.mjs.map +1 -1
- package/dist/endpoint-hooks.cjs +10 -5
- package/dist/endpoint-hooks.cjs.map +1 -1
- package/dist/endpoint-hooks.d.cts +2 -2
- package/dist/endpoint-hooks.d.cts.map +1 -0
- package/dist/endpoint-hooks.d.mts +2 -2
- package/dist/endpoint-hooks.d.mts.map +1 -0
- package/dist/endpoint-hooks.mjs +10 -5
- package/dist/endpoint-hooks.mjs.map +1 -1
- package/dist/{fetcher-DLDD_7Sa.mjs → fetcher-5fnBE7Dk.mjs} +2 -2
- package/dist/fetcher-5fnBE7Dk.mjs.map +1 -0
- package/dist/{fetcher-KdwHgdAl.cjs → fetcher-CgLEaIAC.cjs} +2 -2
- package/dist/fetcher-CgLEaIAC.cjs.map +1 -0
- package/dist/fetcher.cjs +1 -1
- package/dist/fetcher.d.cts +3 -1
- package/dist/fetcher.d.cts.map +1 -0
- package/dist/fetcher.d.mts +3 -1
- package/dist/fetcher.d.mts.map +1 -0
- package/dist/fetcher.mjs +1 -1
- package/dist/infer.d.cts.map +1 -0
- package/dist/infer.d.mts.map +1 -0
- package/dist/openapi-hooks.cjs +3 -5
- package/dist/openapi-hooks.cjs.map +1 -1
- package/dist/openapi-hooks.d.cts +3 -3
- package/dist/openapi-hooks.d.cts.map +1 -0
- package/dist/openapi-hooks.d.mts +6 -6
- package/dist/openapi-hooks.d.mts.map +1 -0
- package/dist/openapi-hooks.mjs +3 -5
- package/dist/openapi-hooks.mjs.map +1 -1
- package/dist/openapi-types.d.cts.map +1 -0
- package/dist/openapi-types.d.mts.map +1 -0
- package/dist/openapi.cjs.map +1 -1
- package/dist/openapi.mjs.map +1 -1
- package/dist/react-query.cjs +1 -1
- package/dist/react-query.cjs.map +1 -1
- package/dist/react-query.d.cts +3 -1
- package/dist/react-query.d.cts.map +1 -0
- package/dist/react-query.d.mts +10 -8
- package/dist/react-query.d.mts.map +1 -0
- package/dist/react-query.mjs +1 -1
- package/dist/react-query.mjs.map +1 -1
- package/dist/{types-D4OSWveN.d.cts → types-4K4N-Fl1.d.cts} +8 -6
- package/dist/types-4K4N-Fl1.d.cts.map +1 -0
- package/dist/{types-Cdv1XAWr.d.mts → types-hhkZWjQn.d.mts} +8 -6
- package/dist/types-hhkZWjQn.d.mts.map +1 -0
- package/dist/types.d.cts +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +6 -5
- package/src/__tests__/auth-fetcher.spec.ts +505 -0
- package/src/__tests__/endpoint-hooks.spec.tsx +348 -348
- package/src/__tests__/fetcher.spec.ts +403 -403
- package/src/__tests__/infer.integration.spec.ts +171 -171
- package/src/__tests__/infer.spec.ts +182 -182
- package/src/__tests__/method-restrictions.spec.tsx +165 -165
- package/src/__tests__/openapi-hooks.spec.tsx +536 -537
- package/src/__tests__/react-query-infinite.spec.tsx +989 -989
- package/src/__tests__/react-query-invalidation.spec.tsx +223 -222
- package/src/__tests__/react-query.spec.tsx +567 -567
- package/src/__tests__/setup.ts +260 -260
- package/src/__tests__/types.spec.ts +127 -127
- package/src/__tests__/url-parsing.spec.ts +191 -191
- package/src/auth-fetcher.ts +160 -162
- package/src/endpoint-hooks.ts +151 -150
- package/src/fetcher.ts +163 -163
- package/src/infer.ts +64 -63
- package/src/openapi-hooks.ts +146 -146
- package/src/openapi-types.d.ts +428 -428
- package/src/openapi.json +593 -593
- package/src/react-query.ts +281 -281
- package/src/types.ts +124 -125
- package/tsconfig.json +12 -0
- package/dist/fetcher-DLDD_7Sa.mjs.map +0 -1
- package/dist/fetcher-KdwHgdAl.cjs.map +0 -1
package/src/types.ts
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
1
|
export type OpenAPIRoutes<Paths> = keyof Paths;
|
|
2
2
|
|
|
3
3
|
type HttpMethod =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
| 'get'
|
|
5
|
+
| 'post'
|
|
6
|
+
| 'put'
|
|
7
|
+
| 'patch'
|
|
8
|
+
| 'delete'
|
|
9
|
+
| 'head'
|
|
10
|
+
| 'options';
|
|
11
11
|
|
|
12
12
|
export type ExtractMethod<Paths, Route extends OpenAPIRoutes<Paths>> = Extract<
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
keyof Paths[Route],
|
|
14
|
+
HttpMethod
|
|
15
15
|
>;
|
|
16
16
|
|
|
17
17
|
export type ExtractPathParams<
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
Paths,
|
|
19
|
+
Route extends OpenAPIRoutes<Paths>,
|
|
20
20
|
> = Paths[Route] extends {
|
|
21
|
-
|
|
21
|
+
parameters?: { path?: infer P };
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
? P
|
|
24
|
+
: never;
|
|
25
25
|
|
|
26
26
|
export type ExtractQueryParams<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
Paths,
|
|
28
|
+
Route extends OpenAPIRoutes<Paths>,
|
|
29
|
+
Method extends ExtractMethod<Paths, Route>,
|
|
30
30
|
> = Paths[Route][Method] extends { parameters?: { query?: infer Q } }
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
? Q
|
|
32
|
+
: never;
|
|
33
33
|
|
|
34
34
|
export type ExtractRequestBody<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
Paths,
|
|
36
|
+
Route extends OpenAPIRoutes<Paths>,
|
|
37
|
+
Method extends ExtractMethod<Paths, Route>,
|
|
38
38
|
> = Paths[Route][Method] extends {
|
|
39
|
-
|
|
39
|
+
requestBody?: { content?: { 'application/json'?: infer B } };
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
? B
|
|
42
|
+
: never;
|
|
43
43
|
|
|
44
44
|
export type ExtractResponse<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
Paths,
|
|
46
|
+
Route extends OpenAPIRoutes<Paths>,
|
|
47
|
+
Method extends ExtractMethod<Paths, Route>,
|
|
48
48
|
> = Paths[Route][Method] extends {
|
|
49
|
-
|
|
49
|
+
responses?: { 200?: { content?: { 'application/json'?: infer R } } };
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
? R
|
|
52
|
+
: Paths[Route][Method] extends {
|
|
53
|
+
responses?: { 201?: { content?: { 'application/json'?: infer R } } };
|
|
54
|
+
}
|
|
55
|
+
? R
|
|
56
|
+
: never;
|
|
57
57
|
|
|
58
58
|
export type RequestConfig<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
Paths,
|
|
60
|
+
Route extends OpenAPIRoutes<Paths>,
|
|
61
|
+
Method extends ExtractMethod<Paths, Route>,
|
|
62
62
|
> = {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
params?: ExtractPathParams<Paths, Route>;
|
|
64
|
+
query?: ExtractQueryParams<Paths, Route, Method>;
|
|
65
|
+
body?: ExtractRequestBody<Paths, Route, Method>;
|
|
66
|
+
headers?: Record<string, string>;
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
export type EndpointString = `${Uppercase<string>} ${string}`;
|
|
@@ -71,66 +71,63 @@ export type EndpointString = `${Uppercase<string>} ${string}`;
|
|
|
71
71
|
// Generate all valid endpoint strings from OpenAPI paths
|
|
72
72
|
// Uses Extract with HttpMethod to filter out non-HTTP keys like 'parameters'
|
|
73
73
|
export type ValidEndpoint<Paths> = {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
79
|
}[keyof Paths];
|
|
80
80
|
|
|
81
81
|
// Helper type to get autocomplete for endpoint strings
|
|
82
|
-
export type TypedEndpoint<Paths> =
|
|
83
|
-
|
|
84
|
-
? E
|
|
85
|
-
: never
|
|
86
|
-
: never;
|
|
82
|
+
export type TypedEndpoint<Paths> =
|
|
83
|
+
ValidEndpoint<Paths> extends infer E ? (E extends string ? E : never) : never;
|
|
87
84
|
|
|
88
85
|
// Filter endpoints by HTTP method
|
|
89
86
|
export type FilterEndpointByMethod<
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
Paths,
|
|
88
|
+
Method extends string,
|
|
92
89
|
> = ValidEndpoint<Paths> extends infer E
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
? E extends `${Method} ${string}`
|
|
91
|
+
? E
|
|
92
|
+
: never
|
|
93
|
+
: never;
|
|
97
94
|
|
|
98
95
|
// Query endpoints (GET only)
|
|
99
96
|
export type QueryEndpoint<Paths> = FilterEndpointByMethod<Paths, 'GET'>;
|
|
100
97
|
|
|
101
98
|
// Mutation endpoints (POST, PATCH, PUT, DELETE)
|
|
102
99
|
export type MutationEndpoint<Paths> =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
| FilterEndpointByMethod<Paths, 'POST'>
|
|
101
|
+
| FilterEndpointByMethod<Paths, 'PATCH'>
|
|
102
|
+
| FilterEndpointByMethod<Paths, 'PUT'>
|
|
103
|
+
| FilterEndpointByMethod<Paths, 'DELETE'>;
|
|
107
104
|
|
|
108
105
|
export type ParseEndpoint<T extends EndpointString> =
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
106
|
+
T extends `${infer Method} ${infer Route}`
|
|
107
|
+
? { method: Lowercase<Method>; route: Route }
|
|
108
|
+
: never;
|
|
112
109
|
|
|
113
110
|
export type ExtractEndpointResponse<
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
Paths,
|
|
112
|
+
T extends EndpointString,
|
|
116
113
|
> = T extends `${infer Method} ${infer Route}`
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
114
|
+
? Route extends OpenAPIRoutes<Paths>
|
|
115
|
+
? Lowercase<Method> extends ExtractMethod<Paths, Route>
|
|
116
|
+
? ExtractResponse<Paths, Route, Lowercase<Method>>
|
|
117
|
+
: never
|
|
118
|
+
: never
|
|
119
|
+
: never;
|
|
123
120
|
|
|
124
121
|
export type ExtractEndpointConfig<
|
|
125
|
-
|
|
126
|
-
|
|
122
|
+
Paths,
|
|
123
|
+
T extends EndpointString,
|
|
127
124
|
> = T extends `${infer Method} ${infer Route}`
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
125
|
+
? Route extends OpenAPIRoutes<Paths>
|
|
126
|
+
? Lowercase<Method> extends ExtractMethod<Paths, Route>
|
|
127
|
+
? RequestConfig<Paths, Route, Lowercase<Method>>
|
|
128
|
+
: never
|
|
129
|
+
: never
|
|
130
|
+
: never;
|
|
134
131
|
|
|
135
132
|
/**
|
|
136
133
|
* Build a request config type where:
|
|
@@ -139,33 +136,35 @@ export type ExtractEndpointConfig<
|
|
|
139
136
|
* - `query` and `headers` are always optional
|
|
140
137
|
*/
|
|
141
138
|
export type FilteredRequestConfig<
|
|
142
|
-
|
|
143
|
-
|
|
139
|
+
Paths,
|
|
140
|
+
T extends EndpointString,
|
|
144
141
|
> = T extends `${infer Method} ${infer Route}`
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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;
|
|
155
152
|
|
|
156
153
|
/**
|
|
157
|
-
* Helper to build request config with correct required/optional fields
|
|
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`.
|
|
158
157
|
*/
|
|
159
158
|
type BuildRequestConfig<TParams, TQuery, TBody> = SimplifyIntersection<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
+
}
|
|
169
168
|
>;
|
|
170
169
|
|
|
171
170
|
/**
|
|
@@ -177,36 +176,36 @@ type SimplifyIntersection<T> = { [K in keyof T]: T[K] };
|
|
|
177
176
|
* Check if the config object is required (has any required fields)
|
|
178
177
|
*/
|
|
179
178
|
export type IsConfigRequired<
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
Paths,
|
|
180
|
+
T extends EndpointString,
|
|
182
181
|
> = T extends `${infer Method} ${infer Route}`
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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;
|
|
193
192
|
|
|
194
193
|
/**
|
|
195
194
|
* Typed function signature for the API client.
|
|
196
195
|
* Config is required when endpoint has path params or body.
|
|
197
196
|
*/
|
|
198
197
|
export type TypedApiFunction<Paths> = <T extends TypedEndpoint<Paths>>(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
198
|
+
endpoint: T,
|
|
199
|
+
...args: IsConfigRequired<Paths, T> extends true
|
|
200
|
+
? [config: FilteredRequestConfig<Paths, T>]
|
|
201
|
+
: [config?: FilteredRequestConfig<Paths, T>]
|
|
203
202
|
) => Promise<ExtractEndpointResponse<Paths, T>>;
|
|
204
203
|
|
|
205
204
|
export interface FetcherOptions {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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;
|
|
212
211
|
}
|
package/tsconfig.json
ADDED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher-DLDD_7Sa.mjs","names":["fn?: FetchFn","options: FetcherOptions","endpoint: T","config?: FilteredRequestConfig<Paths, T>","prefix: string","value: unknown","requestConfig: RequestInit","options?: FetcherOptions"],"sources":["../src/fetcher.ts"],"sourcesContent":["import type {\n EndpointString,\n ExtractEndpointResponse,\n FetcherOptions,\n FilteredRequestConfig,\n ParseEndpoint,\n TypedEndpoint,\n} from './types';\n\nexport type { FetcherOptions } from './types';\n\nexport class TypedFetcher<Paths> {\n private baseURL: string;\n private defaultHeaders: Record<string, string>;\n private options: FetcherOptions;\n private fetchFn: FetchFn;\n\n static getFetchFn(fn?: FetchFn): FetchFn {\n if (fn) {\n return fn;\n }\n\n if (typeof window !== 'undefined' && typeof window.fetch === 'function') {\n return window.fetch.bind(window);\n }\n\n if (\n typeof globalThis !== 'undefined' &&\n typeof globalThis.fetch === 'function'\n ) {\n return globalThis.fetch.bind(globalThis);\n }\n\n throw new Error('No fetch implementation found');\n }\n\n constructor(options: FetcherOptions = {}) {\n this.baseURL = options.baseURL || '';\n this.defaultHeaders = options.headers || {};\n this.options = options;\n this.fetchFn = TypedFetcher.getFetchFn(options.fetch);\n }\n\n async request<T extends TypedEndpoint<Paths>>(\n endpoint: T,\n config?: FilteredRequestConfig<Paths, T>,\n ): Promise<ExtractEndpointResponse<Paths, T>> {\n const { method, route } = this.parseEndpoint(endpoint);\n\n // Replace path parameters\n let url = route;\n if (config && 'params' in config && config.params) {\n Object.entries(config.params as Record<string, unknown>).forEach(\n ([key, value]) => {\n url = url.replace(`{${key}}`, encodeURIComponent(String(value)));\n },\n );\n }\n\n // Add query parameters\n if (config && 'query' in config && config.query) {\n const queryParams = new URLSearchParams();\n\n // Recursive function to handle nested objects and arrays\n const appendQueryParam = (prefix: string, value: unknown) => {\n if (value === undefined || value === null) {\n return;\n }\n\n if (Array.isArray(value)) {\n // Handle arrays by appending multiple values with the same key\n value.forEach((item) => {\n queryParams.append(prefix, String(item));\n });\n } else if (typeof value === 'object') {\n // For objects, recursively flatten into dot notation\n Object.entries(value as Record<string, unknown>).forEach(\n ([subKey, subValue]) => {\n appendQueryParam(`${prefix}.${subKey}`, subValue);\n },\n );\n } else {\n queryParams.append(prefix, String(value));\n }\n };\n\n // Process all query parameters\n Object.entries(config.query as Record<string, unknown>).forEach(\n ([key, value]) => {\n appendQueryParam(key, value);\n },\n );\n\n const queryString = queryParams.toString();\n if (queryString) {\n url += `?${queryString}`;\n }\n }\n\n // Build request configuration\n let requestConfig: RequestInit = {\n method: method.toUpperCase(),\n headers: {\n ...this.defaultHeaders,\n ...((config && 'headers' in config && config.headers) || {}),\n },\n };\n\n // Add body if present\n if (config && 'body' in config && config.body) {\n requestConfig.body = JSON.stringify(config.body);\n requestConfig.headers = {\n ...requestConfig.headers,\n 'Content-Type': 'application/json',\n };\n }\n\n // Apply request interceptor\n if (this.options.onRequest) {\n requestConfig = await this.options.onRequest(requestConfig);\n }\n\n try {\n // Make the request\n let response = await this.fetchFn(`${this.baseURL}${url}`, requestConfig);\n\n // Apply response interceptor\n if (this.options.onResponse) {\n response = await this.options.onResponse(response);\n }\n\n // Handle errors\n if (!response.ok) {\n throw response;\n }\n\n // Handle empty responses (204 No Content, etc.)\n if (\n response.status === 204 ||\n response.headers.get('content-length') === '0'\n ) {\n return undefined as ExtractEndpointResponse<Paths, T>;\n }\n\n // Parse JSON response\n const data = await response.json();\n return data as ExtractEndpointResponse<Paths, T>;\n } catch (error) {\n // Apply error handler\n if (this.options.onError) {\n // @ts-ignore\n await this.options.onError(error);\n }\n throw error;\n }\n }\n\n private parseEndpoint<T extends EndpointString>(\n endpoint: T,\n ): ParseEndpoint<T> {\n const [method, ...routeParts] = endpoint.split(' ');\n const route = routeParts.join(' ');\n return { method: method.toLowerCase(), route } as ParseEndpoint<T>;\n }\n}\n\nexport function createTypedFetcher<Paths>(options?: FetcherOptions) {\n const fetcher = new TypedFetcher<Paths>(options);\n return <T extends TypedEndpoint<Paths>>(\n endpoint: T,\n config?: FilteredRequestConfig<Paths, T>,\n ) => fetcher.request(endpoint, config);\n}\n\nexport type FetchFn = typeof fetch;\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher-KdwHgdAl.cjs","names":["fn?: FetchFn","options: FetcherOptions","endpoint: T","config?: FilteredRequestConfig<Paths, T>","prefix: string","value: unknown","requestConfig: RequestInit","options?: FetcherOptions"],"sources":["../src/fetcher.ts"],"sourcesContent":["import type {\n EndpointString,\n ExtractEndpointResponse,\n FetcherOptions,\n FilteredRequestConfig,\n ParseEndpoint,\n TypedEndpoint,\n} from './types';\n\nexport type { FetcherOptions } from './types';\n\nexport class TypedFetcher<Paths> {\n private baseURL: string;\n private defaultHeaders: Record<string, string>;\n private options: FetcherOptions;\n private fetchFn: FetchFn;\n\n static getFetchFn(fn?: FetchFn): FetchFn {\n if (fn) {\n return fn;\n }\n\n if (typeof window !== 'undefined' && typeof window.fetch === 'function') {\n return window.fetch.bind(window);\n }\n\n if (\n typeof globalThis !== 'undefined' &&\n typeof globalThis.fetch === 'function'\n ) {\n return globalThis.fetch.bind(globalThis);\n }\n\n throw new Error('No fetch implementation found');\n }\n\n constructor(options: FetcherOptions = {}) {\n this.baseURL = options.baseURL || '';\n this.defaultHeaders = options.headers || {};\n this.options = options;\n this.fetchFn = TypedFetcher.getFetchFn(options.fetch);\n }\n\n async request<T extends TypedEndpoint<Paths>>(\n endpoint: T,\n config?: FilteredRequestConfig<Paths, T>,\n ): Promise<ExtractEndpointResponse<Paths, T>> {\n const { method, route } = this.parseEndpoint(endpoint);\n\n // Replace path parameters\n let url = route;\n if (config && 'params' in config && config.params) {\n Object.entries(config.params as Record<string, unknown>).forEach(\n ([key, value]) => {\n url = url.replace(`{${key}}`, encodeURIComponent(String(value)));\n },\n );\n }\n\n // Add query parameters\n if (config && 'query' in config && config.query) {\n const queryParams = new URLSearchParams();\n\n // Recursive function to handle nested objects and arrays\n const appendQueryParam = (prefix: string, value: unknown) => {\n if (value === undefined || value === null) {\n return;\n }\n\n if (Array.isArray(value)) {\n // Handle arrays by appending multiple values with the same key\n value.forEach((item) => {\n queryParams.append(prefix, String(item));\n });\n } else if (typeof value === 'object') {\n // For objects, recursively flatten into dot notation\n Object.entries(value as Record<string, unknown>).forEach(\n ([subKey, subValue]) => {\n appendQueryParam(`${prefix}.${subKey}`, subValue);\n },\n );\n } else {\n queryParams.append(prefix, String(value));\n }\n };\n\n // Process all query parameters\n Object.entries(config.query as Record<string, unknown>).forEach(\n ([key, value]) => {\n appendQueryParam(key, value);\n },\n );\n\n const queryString = queryParams.toString();\n if (queryString) {\n url += `?${queryString}`;\n }\n }\n\n // Build request configuration\n let requestConfig: RequestInit = {\n method: method.toUpperCase(),\n headers: {\n ...this.defaultHeaders,\n ...((config && 'headers' in config && config.headers) || {}),\n },\n };\n\n // Add body if present\n if (config && 'body' in config && config.body) {\n requestConfig.body = JSON.stringify(config.body);\n requestConfig.headers = {\n ...requestConfig.headers,\n 'Content-Type': 'application/json',\n };\n }\n\n // Apply request interceptor\n if (this.options.onRequest) {\n requestConfig = await this.options.onRequest(requestConfig);\n }\n\n try {\n // Make the request\n let response = await this.fetchFn(`${this.baseURL}${url}`, requestConfig);\n\n // Apply response interceptor\n if (this.options.onResponse) {\n response = await this.options.onResponse(response);\n }\n\n // Handle errors\n if (!response.ok) {\n throw response;\n }\n\n // Handle empty responses (204 No Content, etc.)\n if (\n response.status === 204 ||\n response.headers.get('content-length') === '0'\n ) {\n return undefined as ExtractEndpointResponse<Paths, T>;\n }\n\n // Parse JSON response\n const data = await response.json();\n return data as ExtractEndpointResponse<Paths, T>;\n } catch (error) {\n // Apply error handler\n if (this.options.onError) {\n // @ts-ignore\n await this.options.onError(error);\n }\n throw error;\n }\n }\n\n private parseEndpoint<T extends EndpointString>(\n endpoint: T,\n ): ParseEndpoint<T> {\n const [method, ...routeParts] = endpoint.split(' ');\n const route = routeParts.join(' ');\n return { method: method.toLowerCase(), route } as ParseEndpoint<T>;\n }\n}\n\nexport function createTypedFetcher<Paths>(options?: FetcherOptions) {\n const fetcher = new TypedFetcher<Paths>(options);\n return <T extends TypedEndpoint<Paths>>(\n endpoint: T,\n config?: FilteredRequestConfig<Paths, T>,\n ) => fetcher.request(endpoint, config);\n}\n\nexport type FetchFn = typeof fetch;\n"],"mappings":"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"}
|