@openapi-qraft/react 2.0.0-next.8 → 2.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/CHANGELOG.md +154 -1
- package/dist/cjs/callbacks/ensureInfiniteQueryData.cjs +10 -0
- package/dist/cjs/callbacks/ensureInfiniteQueryData.cjs.map +1 -0
- package/dist/cjs/callbacks/ensureQueryData.cjs +10 -0
- package/dist/cjs/callbacks/ensureQueryData.cjs.map +1 -0
- package/dist/cjs/callbacks/index.cjs +4 -0
- package/dist/cjs/callbacks/index.cjs.map +1 -1
- package/dist/cjs/callbacks/useQueries.cjs +1 -0
- package/dist/cjs/callbacks/useQueries.cjs.map +1 -1
- package/dist/cjs/callbacks/useSuspenseQueries.cjs +1 -0
- package/dist/cjs/callbacks/useSuspenseQueries.cjs.map +1 -1
- package/dist/cjs/lib/callQueryClientFetchMethod.cjs.map +1 -1
- package/dist/cjs/lib/requestFn.cjs +67 -64
- package/dist/cjs/lib/requestFn.cjs.map +1 -1
- package/dist/cjs/lib/responseUtils.cjs +41 -0
- package/dist/cjs/lib/responseUtils.cjs.map +1 -0
- package/dist/cjs/lib/useComposeUseQueryOptions.cjs +1 -2
- package/dist/cjs/lib/useComposeUseQueryOptions.cjs.map +1 -1
- package/dist/cjs/qraftAPIClient.cjs +2 -2
- package/dist/cjs/qraftAPIClient.cjs.map +1 -1
- package/dist/cjs/unstable__responseUtils.cjs +9 -0
- package/dist/cjs/unstable__responseUtils.cjs.map +1 -0
- package/dist/esm/callbacks/ensureInfiniteQueryData.js +8 -0
- package/dist/esm/callbacks/ensureInfiniteQueryData.js.map +1 -0
- package/dist/esm/callbacks/ensureQueryData.js +8 -0
- package/dist/esm/callbacks/ensureQueryData.js.map +1 -0
- package/dist/esm/callbacks/index.js +2 -0
- package/dist/esm/callbacks/index.js.map +1 -1
- package/dist/esm/callbacks/useQueries.js +1 -0
- package/dist/esm/callbacks/useQueries.js.map +1 -1
- package/dist/esm/callbacks/useSuspenseQueries.js +1 -0
- package/dist/esm/callbacks/useSuspenseQueries.js.map +1 -1
- package/dist/esm/lib/callQueryClientFetchMethod.js.map +1 -1
- package/dist/esm/lib/requestFn.js +66 -63
- package/dist/esm/lib/requestFn.js.map +1 -1
- package/dist/esm/lib/responseUtils.js +38 -0
- package/dist/esm/lib/responseUtils.js.map +1 -0
- package/dist/esm/lib/useComposeUseQueryOptions.js +1 -2
- package/dist/esm/lib/useComposeUseQueryOptions.js.map +1 -1
- package/dist/esm/qraftAPIClient.js +2 -2
- package/dist/esm/qraftAPIClient.js.map +1 -1
- package/dist/esm/unstable__responseUtils.js +2 -0
- package/dist/esm/unstable__responseUtils.js.map +1 -0
- package/dist/types/callbacks/ensureInfiniteQueryData.d.ts +8 -0
- package/dist/types/callbacks/ensureInfiniteQueryData.d.ts.map +1 -0
- package/dist/types/callbacks/ensureQueryData.d.ts +8 -0
- package/dist/types/callbacks/ensureQueryData.d.ts.map +1 -0
- package/dist/types/callbacks/index.d.ts +2 -0
- package/dist/types/callbacks/index.d.ts.map +1 -1
- package/dist/types/callbacks/useQueries.d.ts.map +1 -1
- package/dist/types/callbacks/useSuspenseQueries.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/callQueryClientFetchMethod.d.ts +1 -1
- package/dist/types/lib/callQueryClientFetchMethod.d.ts.map +1 -1
- package/dist/types/lib/requestFn.d.ts +24 -5
- package/dist/types/lib/requestFn.d.ts.map +1 -1
- package/dist/types/lib/responseUtils.d.ts +13 -0
- package/dist/types/lib/responseUtils.d.ts.map +1 -0
- package/dist/types/lib/useComposeUseQueryOptions.d.ts.map +1 -1
- package/dist/types/qraftAPIClient.d.ts +1 -1
- package/dist/types/qraftAPIClient.d.ts.map +1 -1
- package/dist/types/unstable__responseUtils.d.ts +2 -0
- package/dist/types/unstable__responseUtils.d.ts.map +1 -0
- package/package.json +24 -19
- package/src/callbacks/ensureInfiniteQueryData.ts +29 -0
- package/src/callbacks/ensureQueryData.ts +29 -0
- package/src/callbacks/index.ts +2 -0
- package/src/callbacks/useQueries.ts +1 -0
- package/src/callbacks/useSuspenseQueries.ts +1 -0
- package/src/index.ts +6 -8
- package/src/lib/callQueryClientFetchMethod.ts +3 -1
- package/src/lib/requestFn.ts +96 -120
- package/src/lib/responseUtils.ts +74 -0
- package/src/lib/useComposeUseQueryOptions.ts +0 -1
- package/src/qraftAPIClient.ts +5 -2
- package/src/unstable__responseUtils.ts +1 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openapi-qraft/react",
|
|
3
|
-
"version": "2.0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "OpenAPI client for React, providing type-safe requests and dynamic TanStack Query React Hooks via a modular, Proxy-based architecture.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "NODE_ENV=production rollup --config rollup.config.mjs && tsc --project tsconfig.build.json --emitDeclarationOnly",
|
|
7
7
|
"dev": "rimraf dist/ && tsc --project tsconfig.build.json --watch --outDir ./dist/esm --noEmitOnError false",
|
|
@@ -15,34 +15,34 @@
|
|
|
15
15
|
},
|
|
16
16
|
"sideEffects": false,
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@openapi-qraft/tanstack-query-react-types": "2.0.0
|
|
18
|
+
"@openapi-qraft/tanstack-query-react-types": "2.0.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@openapi-qraft/cli": "2.0.0
|
|
21
|
+
"@openapi-qraft/cli": "2.0.0",
|
|
22
22
|
"@openapi-qraft/eslint-config": "1.0.0",
|
|
23
|
-
"@openapi-qraft/openapi-typescript-plugin": "^1.2.0
|
|
24
|
-
"@openapi-qraft/rollup-config": "1.1.0
|
|
25
|
-
"@openapi-qraft/tanstack-query-react-plugin": "2.0.0
|
|
23
|
+
"@openapi-qraft/openapi-typescript-plugin": "^1.2.0",
|
|
24
|
+
"@openapi-qraft/rollup-config": "1.1.0",
|
|
25
|
+
"@openapi-qraft/tanstack-query-react-plugin": "2.0.0",
|
|
26
26
|
"@openapi-qraft/test-fixtures": "1.0.0",
|
|
27
|
-
"@tanstack/react-query": "^5.
|
|
27
|
+
"@tanstack/react-query": "^5.56.2",
|
|
28
28
|
"@testing-library/jest-dom": "^5.17.0",
|
|
29
29
|
"@testing-library/react": "^13.4.0",
|
|
30
30
|
"@testing-library/user-event": "^14.5.2",
|
|
31
31
|
"@types/jscodeshift": "^0.11.11",
|
|
32
|
-
"@types/react": "^18.
|
|
33
|
-
"@vitejs/plugin-react": "
|
|
34
|
-
"@vitest/coverage-v8": "^
|
|
35
|
-
"eslint": "^9.
|
|
36
|
-
"globals": "^15.
|
|
32
|
+
"@types/react": "^18.3.5",
|
|
33
|
+
"@vitejs/plugin-react": "^4.3.1",
|
|
34
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
35
|
+
"eslint": "^9.16.0",
|
|
36
|
+
"globals": "^15.9.0",
|
|
37
37
|
"jscodeshift": "^17.0.0",
|
|
38
|
-
"jsdom": "
|
|
39
|
-
"msw": "^2.
|
|
38
|
+
"jsdom": "^25.0.0",
|
|
39
|
+
"msw": "^2.6.8",
|
|
40
40
|
"prettier": "^3.3.3",
|
|
41
|
-
"query-string": "^8.
|
|
42
|
-
"react": "^18.
|
|
41
|
+
"query-string": "^8.2.0",
|
|
42
|
+
"react": "^18.3.1",
|
|
43
43
|
"rimraf": "^5.0.10",
|
|
44
|
-
"rollup": "~4.
|
|
45
|
-
"vitest": "^1.
|
|
44
|
+
"rollup": "~4.22.4",
|
|
45
|
+
"vitest": "^2.1.8"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@tanstack/query-core": "^5.0.0",
|
|
@@ -77,6 +77,11 @@
|
|
|
77
77
|
"require": "./dist/cjs/qraftPredefinedParametersRequestFn.cjs",
|
|
78
78
|
"types": "./dist/types/qraftPredefinedParametersRequestFn.d.ts"
|
|
79
79
|
},
|
|
80
|
+
"./unstable__responseUtils": {
|
|
81
|
+
"import": "./dist/esm/unstable__responseUtils.js",
|
|
82
|
+
"require": "./dist/cjs/unstable__responseUtils.cjs",
|
|
83
|
+
"types": "./dist/types/unstable__responseUtils.d.ts"
|
|
84
|
+
},
|
|
80
85
|
"./package.json": "./package.json"
|
|
81
86
|
},
|
|
82
87
|
"typesVersions": {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ServiceOperationFetchInfiniteQuery } from '@openapi-qraft/tanstack-query-react-types';
|
|
2
|
+
import type { DefaultError } from '@tanstack/query-core';
|
|
3
|
+
import type { CreateAPIQueryClientOptions } from '../qraftAPIClient.js';
|
|
4
|
+
import { callQueryClientMethodWithQueryKey } from '../lib/callQueryClientFetchMethod.js';
|
|
5
|
+
|
|
6
|
+
export const ensureInfiniteQueryData: <
|
|
7
|
+
TSchema extends { url: string; method: 'get' | 'head' | 'options' },
|
|
8
|
+
TData,
|
|
9
|
+
TParams,
|
|
10
|
+
>(
|
|
11
|
+
qraftOptions: CreateAPIQueryClientOptions,
|
|
12
|
+
schema: TSchema,
|
|
13
|
+
args: Parameters<
|
|
14
|
+
ServiceOperationFetchInfiniteQuery<
|
|
15
|
+
TSchema,
|
|
16
|
+
TData,
|
|
17
|
+
TParams,
|
|
18
|
+
DefaultError
|
|
19
|
+
>['ensureInfiniteQueryData']
|
|
20
|
+
>
|
|
21
|
+
) => Promise<TData> = (qraftOptions, schema, args) => {
|
|
22
|
+
return callQueryClientMethodWithQueryKey(
|
|
23
|
+
qraftOptions,
|
|
24
|
+
'ensureInfiniteQueryData',
|
|
25
|
+
schema,
|
|
26
|
+
true,
|
|
27
|
+
args as never
|
|
28
|
+
) as never;
|
|
29
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ServiceOperationFetchQuery } from '@openapi-qraft/tanstack-query-react-types';
|
|
2
|
+
import type { DefaultError } from '@tanstack/query-core';
|
|
3
|
+
import type { CreateAPIQueryClientOptions } from '../qraftAPIClient.js';
|
|
4
|
+
import { callQueryClientMethodWithQueryKey } from '../lib/callQueryClientFetchMethod.js';
|
|
5
|
+
|
|
6
|
+
export const ensureQueryData: <
|
|
7
|
+
TSchema extends { url: string; method: 'get' | 'head' | 'options' },
|
|
8
|
+
TData,
|
|
9
|
+
TParams,
|
|
10
|
+
>(
|
|
11
|
+
qraftOptions: CreateAPIQueryClientOptions,
|
|
12
|
+
schema: TSchema,
|
|
13
|
+
args: Parameters<
|
|
14
|
+
ServiceOperationFetchQuery<
|
|
15
|
+
TSchema,
|
|
16
|
+
TData,
|
|
17
|
+
TParams,
|
|
18
|
+
DefaultError
|
|
19
|
+
>['ensureQueryData']
|
|
20
|
+
>
|
|
21
|
+
) => Promise<TData> = (qraftOptions, schema, args) => {
|
|
22
|
+
return callQueryClientMethodWithQueryKey(
|
|
23
|
+
qraftOptions,
|
|
24
|
+
'ensureQueryData',
|
|
25
|
+
schema,
|
|
26
|
+
false,
|
|
27
|
+
args as never
|
|
28
|
+
) as never;
|
|
29
|
+
};
|
package/src/callbacks/index.ts
CHANGED
|
@@ -26,8 +26,10 @@ export { isMutating } from './isMutating.js';
|
|
|
26
26
|
export { useIsFetching } from './useIsFetching.js';
|
|
27
27
|
export { fetchQuery } from './fetchQuery.js';
|
|
28
28
|
export { prefetchQuery } from './prefetchQuery.js';
|
|
29
|
+
export { ensureQueryData } from './ensureQueryData.js';
|
|
29
30
|
export { fetchInfiniteQuery } from './fetchInfiniteQuery.js';
|
|
30
31
|
export { prefetchInfiniteQuery } from './prefetchInfiniteQuery.js';
|
|
32
|
+
export { ensureInfiniteQueryData } from './ensureInfiniteQueryData.js';
|
|
31
33
|
export { getQueryState } from './getQueryState.js';
|
|
32
34
|
export { getInfiniteQueryState } from './getInfiniteQueryState.js';
|
|
33
35
|
export { operationInvokeFn } from './operationInvokeFn.js';
|
package/src/index.ts
CHANGED
|
@@ -16,13 +16,11 @@ export {
|
|
|
16
16
|
urlSerializer,
|
|
17
17
|
bodySerializer,
|
|
18
18
|
mergeHeaders,
|
|
19
|
+
type RequestFn,
|
|
19
20
|
type RequestFnResponse,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
HeadersOptions,
|
|
26
|
-
OperationSchema,
|
|
27
|
-
RequestFn,
|
|
21
|
+
type HeadersOptions,
|
|
22
|
+
type RequestFnOptions,
|
|
23
|
+
type RequestFnInfo,
|
|
24
|
+
type OperationSchema,
|
|
25
|
+
type RequestFnPayload,
|
|
28
26
|
} from './lib/requestFn.js';
|
|
@@ -84,8 +84,10 @@ type QueryClientMethodArgs<QMethod extends keyof QueryClientPrototype> = [
|
|
|
84
84
|
type QueryKeyMethods =
|
|
85
85
|
| QueryKeyMethod<'fetchQuery'>
|
|
86
86
|
| QueryKeyMethod<'prefetchQuery'>
|
|
87
|
+
| QueryKeyMethod<'ensureQueryData'>
|
|
87
88
|
| QueryKeyMethod<'fetchInfiniteQuery'>
|
|
88
|
-
| QueryKeyMethod<'prefetchInfiniteQuery'
|
|
89
|
+
| QueryKeyMethod<'prefetchInfiniteQuery'>
|
|
90
|
+
| QueryKeyMethod<'ensureInfiniteQueryData'>;
|
|
89
91
|
|
|
90
92
|
type QueryClientPrototype = typeof QueryClient.prototype;
|
|
91
93
|
|
package/src/lib/requestFn.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
HeadersOptions,
|
|
3
3
|
OperationSchema,
|
|
4
|
-
RequestFn,
|
|
5
4
|
RequestFnInfo,
|
|
6
5
|
RequestFnOptions,
|
|
7
|
-
RequestFnPayload,
|
|
8
6
|
RequestFnResponse,
|
|
9
7
|
} from '@openapi-qraft/tanstack-query-react-types';
|
|
8
|
+
import { processResponse, resolveResponse } from './responseUtils.js';
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* This function is used to make a request to a specified endpoint.
|
|
@@ -35,7 +34,7 @@ export async function requestFn<TData, TError>(
|
|
|
35
34
|
|
|
36
35
|
/**
|
|
37
36
|
* This function is used to make a request to a specified endpoint.
|
|
38
|
-
* It's
|
|
37
|
+
* It's necessary to create a custom `requestFn` with a custom `urlSerializer`
|
|
39
38
|
* and `bodySerializer`, with the tree-shaking of the default `requestFn`
|
|
40
39
|
* and its serializers.
|
|
41
40
|
*
|
|
@@ -56,24 +55,18 @@ export async function baseRequestFn<TData, TError>(
|
|
|
56
55
|
): Promise<RequestFnResponse<TData, TError>> {
|
|
57
56
|
const { parameters, headers, body, ...requestInfoRest } = requestInfo;
|
|
58
57
|
|
|
59
|
-
const
|
|
58
|
+
const requestPayload = options.bodySerializer(requestSchema, body);
|
|
60
59
|
|
|
61
60
|
const baseFetch = options.fetch ?? fetch;
|
|
62
61
|
|
|
63
62
|
return baseFetch(options.urlSerializer(requestSchema, requestInfo), {
|
|
64
63
|
method: requestSchema.method.toUpperCase(),
|
|
65
|
-
body:
|
|
64
|
+
body: requestPayload?.body,
|
|
66
65
|
headers: mergeHeaders(
|
|
67
|
-
{
|
|
68
|
-
|
|
69
|
-
'Content-Type': requestSchema.mediaType ?? getBodyContentType(body),
|
|
70
|
-
},
|
|
66
|
+
{ Accept: 'application/json' },
|
|
67
|
+
requestPayload?.headers,
|
|
71
68
|
headers,
|
|
72
|
-
parameters?.header
|
|
73
|
-
requestBody instanceof FormData
|
|
74
|
-
? // remove `Content-Type` if the serialized body is FormData; the browser will correctly set Content-Type & boundary expression
|
|
75
|
-
{ 'Content-Type': null }
|
|
76
|
-
: undefined
|
|
69
|
+
parameters?.header
|
|
77
70
|
),
|
|
78
71
|
...requestInfoRest,
|
|
79
72
|
})
|
|
@@ -98,7 +91,7 @@ export async function baseRequestFn<TData, TError>(
|
|
|
98
91
|
*/
|
|
99
92
|
export function urlSerializer(
|
|
100
93
|
schema: OperationSchema,
|
|
101
|
-
info:
|
|
94
|
+
info: Pick<RequestFnInfo, 'baseUrl' | 'parameters'>
|
|
102
95
|
): string {
|
|
103
96
|
const path = schema.url.replace(
|
|
104
97
|
/{(.*?)}/g,
|
|
@@ -183,47 +176,101 @@ export function mergeHeaders(...allHeaders: (HeadersOptions | undefined)[]) {
|
|
|
183
176
|
|
|
184
177
|
export function bodySerializer(
|
|
185
178
|
schema: OperationSchema,
|
|
186
|
-
|
|
179
|
+
body: RequestFnInfo['body']
|
|
187
180
|
) {
|
|
188
|
-
if (info.body === undefined) return;
|
|
189
|
-
|
|
190
181
|
if (
|
|
191
182
|
schema.method === 'get' ||
|
|
192
183
|
schema.method === 'head' ||
|
|
193
184
|
schema.method === 'options'
|
|
194
185
|
)
|
|
195
|
-
return;
|
|
186
|
+
return undefined;
|
|
187
|
+
|
|
188
|
+
if (body === undefined || body === null) return undefined;
|
|
189
|
+
|
|
190
|
+
if (typeof body === 'string') {
|
|
191
|
+
return {
|
|
192
|
+
body,
|
|
193
|
+
headers: {
|
|
194
|
+
'Content-Type':
|
|
195
|
+
// prefer text/* media type
|
|
196
|
+
schema.mediaType?.find((mediaType) => mediaType.includes('text/')) ??
|
|
197
|
+
// prefer JSON media type, assume that body is serialized as JSON
|
|
198
|
+
schema.mediaType?.find((mediaType) => mediaType.includes('/json')) ??
|
|
199
|
+
'text/plain',
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
196
203
|
|
|
197
|
-
if (
|
|
198
|
-
return
|
|
204
|
+
if (body instanceof FormData) {
|
|
205
|
+
return {
|
|
206
|
+
body,
|
|
207
|
+
headers: {
|
|
208
|
+
// remove `Content-Type` if the serialized body is FormData;
|
|
209
|
+
// the browser will correctly set Content-Type & boundary expression
|
|
210
|
+
'Content-Type': null,
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
}
|
|
199
214
|
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
215
|
+
if (body instanceof Blob) {
|
|
216
|
+
return {
|
|
217
|
+
body,
|
|
218
|
+
headers: {
|
|
219
|
+
'Content-Type':
|
|
220
|
+
body.type ||
|
|
221
|
+
schema.mediaType?.find(
|
|
222
|
+
(mediaType) =>
|
|
223
|
+
!(
|
|
224
|
+
mediaType.includes('text/') &&
|
|
225
|
+
mediaType.includes('/form-data') &&
|
|
226
|
+
mediaType.includes('/json')
|
|
227
|
+
)
|
|
228
|
+
) ||
|
|
229
|
+
'application/octet-stream',
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
let jsonMediaType: string | null = null;
|
|
235
|
+
let formDataMediaType: string | null = null;
|
|
236
|
+
|
|
237
|
+
if (schema.mediaType) {
|
|
238
|
+
for (let i = 0; i < schema.mediaType.length; i++) {
|
|
239
|
+
const mediaType = schema.mediaType[i];
|
|
240
|
+
if (mediaType.includes('/json')) jsonMediaType = mediaType;
|
|
241
|
+
else if (mediaType.includes('/form-data')) formDataMediaType = mediaType;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (formDataMediaType) {
|
|
246
|
+
if (
|
|
247
|
+
!jsonMediaType ||
|
|
248
|
+
// Prefer FormData serialization if one of the fields is a Blob
|
|
249
|
+
Object.values(body).some((value) => value instanceof Blob)
|
|
250
|
+
) {
|
|
251
|
+
return {
|
|
252
|
+
body: getRequestBodyFormData(body),
|
|
253
|
+
headers: {
|
|
254
|
+
// remove `Content-Type` if the serialized body is FormData;
|
|
255
|
+
// the browser will correctly set Content-Type & boundary expression
|
|
256
|
+
'Content-Type': null,
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
207
260
|
}
|
|
208
261
|
|
|
209
|
-
return
|
|
262
|
+
return {
|
|
263
|
+
body: JSON.stringify(body),
|
|
264
|
+
headers: {
|
|
265
|
+
'Content-Type': jsonMediaType ?? 'application/json',
|
|
266
|
+
},
|
|
267
|
+
};
|
|
210
268
|
}
|
|
211
269
|
|
|
212
|
-
function getRequestBodyFormData(
|
|
213
|
-
body
|
|
214
|
-
|
|
270
|
+
function getRequestBodyFormData(
|
|
271
|
+
body: NonNullable<RequestFnInfo['body']>
|
|
272
|
+
): FormData {
|
|
215
273
|
if (body instanceof FormData) return body;
|
|
216
|
-
if (body === null) return;
|
|
217
|
-
|
|
218
|
-
if (body instanceof Blob) throw new Error('Blob not supported in form-data');
|
|
219
|
-
if (body instanceof ArrayBuffer)
|
|
220
|
-
throw new Error('ArrayBuffer not supported in form-data');
|
|
221
|
-
if (body instanceof URLSearchParams)
|
|
222
|
-
throw new Error('URLSearchParams not supported in form-data');
|
|
223
|
-
if (body instanceof ReadableStream)
|
|
224
|
-
throw new Error('ReadableStream not supported in form-data');
|
|
225
|
-
if (typeof body === 'string')
|
|
226
|
-
throw new Error('String not supported in form-data');
|
|
227
274
|
if (typeof body !== 'object')
|
|
228
275
|
throw new Error(`Unsupported body type ${typeof body} in form-data.`);
|
|
229
276
|
|
|
@@ -250,81 +297,6 @@ function getRequestBodyFormData({
|
|
|
250
297
|
return formData;
|
|
251
298
|
}
|
|
252
299
|
|
|
253
|
-
function getBodyContentType(body: RequestFnPayload['body']) {
|
|
254
|
-
if (!body) return;
|
|
255
|
-
if (body instanceof Blob) return body.type || 'application/octet-stream';
|
|
256
|
-
if (typeof body === 'string') return 'text/plain';
|
|
257
|
-
if (!(body instanceof FormData)) return 'application/json';
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
async function processResponse<TData, TError>(
|
|
261
|
-
response: Response
|
|
262
|
-
): Promise<RequestFnResponse<TData, TError>> {
|
|
263
|
-
if (response.status === 204 || response.headers.get('Content-Length') === '0')
|
|
264
|
-
return (
|
|
265
|
-
response.ok ? { data: {}, response } : { error: {}, response }
|
|
266
|
-
) as RequestFnResponse<TData, TError>;
|
|
267
|
-
|
|
268
|
-
if (isJsonResponse(response)) {
|
|
269
|
-
// clone response before parsing every time to allow multiple reads
|
|
270
|
-
const jsonResponse = response.clone().json();
|
|
271
|
-
return resolveResponse(
|
|
272
|
-
response,
|
|
273
|
-
response.ok ? jsonResponse : Promise.reject(await jsonResponse)
|
|
274
|
-
);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const jsonResponse = new Promise<TData>((resolve, reject) =>
|
|
278
|
-
// attempt to parse JSON for successful responses, otherwise fail
|
|
279
|
-
response.clone().text().then(JSON.parse).then(resolve, reject)
|
|
280
|
-
);
|
|
281
|
-
|
|
282
|
-
return resolveResponse(
|
|
283
|
-
response,
|
|
284
|
-
response.ok ? jsonResponse : Promise.reject(await jsonResponse)
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function isJsonResponse(response: Response) {
|
|
289
|
-
const contentType = response.headers.get('Content-Type')?.toLowerCase();
|
|
290
|
-
return contentType?.includes('/json') || contentType?.includes('+json');
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function resolveResponse<TData, TError>(
|
|
294
|
-
error: Error
|
|
295
|
-
): Promise<RequestFnResponse<TData, TError>>;
|
|
296
|
-
function resolveResponse<TData, TError>(
|
|
297
|
-
responseToReturn: Response,
|
|
298
|
-
responsePromise: Promise<TData>
|
|
299
|
-
): Promise<RequestFnResponse<TData, TError>>;
|
|
300
|
-
function resolveResponse<TData, TError>(
|
|
301
|
-
responseToReturn: Response | Error,
|
|
302
|
-
responsePromise?: Promise<TData>
|
|
303
|
-
): Promise<RequestFnResponse<TData, TError>> {
|
|
304
|
-
if (!responsePromise)
|
|
305
|
-
return Promise.reject({
|
|
306
|
-
error: responseToReturn,
|
|
307
|
-
response: undefined,
|
|
308
|
-
data: undefined,
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
return responsePromise
|
|
312
|
-
.then(
|
|
313
|
-
(data) =>
|
|
314
|
-
({ data, response: responseToReturn }) as RequestFnResponse<
|
|
315
|
-
TData,
|
|
316
|
-
TError
|
|
317
|
-
>
|
|
318
|
-
)
|
|
319
|
-
.catch(
|
|
320
|
-
(error) =>
|
|
321
|
-
({ error, response: responseToReturn }) as RequestFnResponse<
|
|
322
|
-
TData,
|
|
323
|
-
TError
|
|
324
|
-
>
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
300
|
type WithRequired<T, K extends keyof T> = T & {
|
|
329
301
|
[_ in K]: {};
|
|
330
302
|
};
|
|
@@ -333,8 +305,12 @@ export type {
|
|
|
333
305
|
RequestFn,
|
|
334
306
|
RequestFnResponse,
|
|
335
307
|
HeadersOptions,
|
|
336
|
-
RequestFnPayload,
|
|
337
308
|
RequestFnOptions,
|
|
338
309
|
RequestFnInfo,
|
|
339
310
|
OperationSchema,
|
|
340
|
-
};
|
|
311
|
+
} from '@openapi-qraft/tanstack-query-react-types';
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* @deprecated use `RequestFnInfo` instead
|
|
315
|
+
*/
|
|
316
|
+
export type RequestFnPayload = RequestFnInfo;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { RequestFnResponse } from '@openapi-qraft/tanstack-query-react-types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Processes the response from the server.
|
|
5
|
+
* @beta
|
|
6
|
+
*/
|
|
7
|
+
export async function processResponse<TData, TError>(
|
|
8
|
+
response: Response
|
|
9
|
+
): Promise<RequestFnResponse<TData, TError>> {
|
|
10
|
+
if (response.status === 204 || response.headers.get('Content-Length') === '0')
|
|
11
|
+
return (
|
|
12
|
+
response.ok ? { data: {}, response } : { error: {}, response }
|
|
13
|
+
) as RequestFnResponse<TData, TError>;
|
|
14
|
+
|
|
15
|
+
const contentType = response.headers.get('Content-Type')?.toLowerCase();
|
|
16
|
+
|
|
17
|
+
const isJsonResponse =
|
|
18
|
+
contentType?.includes('/json') || contentType?.includes('+json');
|
|
19
|
+
|
|
20
|
+
if (isJsonResponse) {
|
|
21
|
+
// clone response before parsing every time to allow multiple reads
|
|
22
|
+
const jsonResponse = response.clone().json();
|
|
23
|
+
return resolveResponse(
|
|
24
|
+
response,
|
|
25
|
+
response.ok ? jsonResponse : Promise.reject(await jsonResponse)
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const textResponse = response.clone().text() as Promise<TData>;
|
|
30
|
+
|
|
31
|
+
return resolveResponse(
|
|
32
|
+
response,
|
|
33
|
+
response.ok ? textResponse : Promise.reject(await textResponse)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Resolves the response from the server.
|
|
39
|
+
* @beta
|
|
40
|
+
*/
|
|
41
|
+
export function resolveResponse<TData, TError>(
|
|
42
|
+
error: Error
|
|
43
|
+
): Promise<RequestFnResponse<TData, TError>>;
|
|
44
|
+
export function resolveResponse<TData, TError>(
|
|
45
|
+
responseToReturn: Response,
|
|
46
|
+
responsePromise: Promise<TData>
|
|
47
|
+
): Promise<RequestFnResponse<TData, TError>>;
|
|
48
|
+
export function resolveResponse<TData, TError>(
|
|
49
|
+
responseToReturn: Response | Error,
|
|
50
|
+
responsePromise?: Promise<TData>
|
|
51
|
+
): Promise<RequestFnResponse<TData, TError>> {
|
|
52
|
+
if (!responsePromise)
|
|
53
|
+
return Promise.reject({
|
|
54
|
+
error: responseToReturn,
|
|
55
|
+
response: undefined,
|
|
56
|
+
data: undefined,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return responsePromise
|
|
60
|
+
.then(
|
|
61
|
+
(data) =>
|
|
62
|
+
({ data, response: responseToReturn }) as RequestFnResponse<
|
|
63
|
+
TData,
|
|
64
|
+
TError
|
|
65
|
+
>
|
|
66
|
+
)
|
|
67
|
+
.catch(
|
|
68
|
+
(error) =>
|
|
69
|
+
({ error, response: responseToReturn }) as RequestFnResponse<
|
|
70
|
+
TData,
|
|
71
|
+
TError
|
|
72
|
+
>
|
|
73
|
+
);
|
|
74
|
+
}
|
package/src/qraftAPIClient.ts
CHANGED
|
@@ -116,11 +116,12 @@ export function qraftAPIClient<
|
|
|
116
116
|
if (
|
|
117
117
|
callbackName !== 'operationInvokeFn' &&
|
|
118
118
|
callbackName !== 'getQueryKey' &&
|
|
119
|
-
callbackName !== 'getMutationKey'
|
|
119
|
+
callbackName !== 'getMutationKey' &&
|
|
120
|
+
callbackName !== 'getInfiniteQueryKey'
|
|
120
121
|
)
|
|
121
122
|
if (!options || !('queryClient' in options && options.queryClient))
|
|
122
123
|
throw new Error(
|
|
123
|
-
`'qraft.<service>.<operation>.${String(callbackName)}()' requires 'queryClient' in options.`
|
|
124
|
+
`'qraft.<service>.<operation>.${String(callbackName)}()' requires 'queryClient' in 'createAPIClient(...)' options.`
|
|
124
125
|
);
|
|
125
126
|
|
|
126
127
|
// @ts-expect-error - Too complex union type
|
|
@@ -223,6 +224,8 @@ type QueryOperationCallbacks = Extract<
|
|
|
223
224
|
| 'prefetchInfiniteQuery'
|
|
224
225
|
| 'prefetchQuery'
|
|
225
226
|
| 'refetchQueries'
|
|
227
|
+
| 'ensureQueryData'
|
|
228
|
+
| 'ensureInfiniteQueryData'
|
|
226
229
|
| 'removeQueries'
|
|
227
230
|
| 'resetQueries'
|
|
228
231
|
| 'setInfiniteQueryData'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { resolveResponse, processResponse } from './lib/responseUtils.js';
|