@qualisero/openapi-endpoint 0.13.2 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -236
- package/dist/cli.js +748 -202
- package/dist/index.d.ts +9 -36
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -58
- package/dist/openapi-helpers.d.ts +4 -17
- package/dist/openapi-helpers.d.ts.map +1 -1
- package/dist/openapi-helpers.js +3 -125
- package/dist/openapi-mutation.d.ts +28 -59
- package/dist/openapi-mutation.d.ts.map +1 -1
- package/dist/openapi-mutation.js +67 -83
- package/dist/openapi-query.d.ts +22 -50
- package/dist/openapi-query.d.ts.map +1 -1
- package/dist/openapi-query.js +22 -55
- package/dist/openapi-utils.d.ts +2 -1
- package/dist/openapi-utils.d.ts.map +1 -1
- package/dist/types.d.ts +218 -475
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -28
- package/package.json +3 -2
package/dist/openapi-mutation.js
CHANGED
|
@@ -1,64 +1,43 @@
|
|
|
1
1
|
import { computed, ref } from 'vue';
|
|
2
2
|
import { useMutation } from '@tanstack/vue-query';
|
|
3
|
-
import { HttpMethod, } from './types.js';
|
|
3
|
+
import { HttpMethod, isMutationMethod, } from './types.js';
|
|
4
4
|
import { isPathResolved, normalizeParamsOptions, useResolvedOperation, resolvePath, generateQueryKey, } from './openapi-utils.js';
|
|
5
5
|
/**
|
|
6
|
-
* Execute a type-safe mutation (POST/PUT/PATCH/DELETE) with automatic cache
|
|
6
|
+
* Execute a type-safe mutation (POST/PUT/PATCH/DELETE) with automatic cache management.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* This is a low-level primitive — in normal usage it is called by the generated
|
|
9
|
+
* per-operation `useMutation` wrappers in `api-client.ts`, not directly.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* @template TResponse The response data type
|
|
12
|
+
* @template TPathParams The path parameters type (concrete, required values)
|
|
13
|
+
* @template TRequest The request body type (`never` if no body)
|
|
14
|
+
* @template TQueryParams The query parameters type
|
|
13
15
|
*
|
|
14
|
-
* @
|
|
15
|
-
* @
|
|
16
|
-
* @param
|
|
17
|
-
* @param h - OpenAPI helpers (internal), provided by useOpenApi
|
|
18
|
-
* @param pathParams - Path parameters (can be reactive). Omit for operations without path params.
|
|
19
|
-
* @param options - Mutation options (dontInvalidate, refetchEndpoints, etc.)
|
|
20
|
-
* - `dontUpdateCache`: Skip cache update for PUT/PATCH responses
|
|
21
|
-
* - `dontInvalidate`: Skip invalidating matching queries
|
|
22
|
-
* - `invalidateOperations`: Additional operation IDs to invalidate (array or map of params)
|
|
23
|
-
* - `refetchEndpoints`: Additional query results to refetch
|
|
24
|
-
* - `queryParams`: Query string parameters (operation-specific)
|
|
25
|
-
* - `axiosOptions`: Custom axios request options (headers, params, etc.)
|
|
26
|
-
* - Plus all {@link UseMutationOptions} from @tanstack/vue-query
|
|
27
|
-
* @throws Error if the operation is not a mutation operation
|
|
28
|
-
* @returns Mutation object with
|
|
29
|
-
* - `mutate(vars)` / `mutateAsync(vars)` to trigger the mutation
|
|
30
|
-
* - `data`: ComputedRef of Axios response data
|
|
31
|
-
* - `isEnabled`: ComputedRef indicating if mutation can execute (path resolved)
|
|
32
|
-
* - `extraPathParams`: Ref to set additional path params at call time
|
|
33
|
-
* - `pathParams`: Resolved path params as a computed ref
|
|
16
|
+
* @param config Endpoint config: axios instance, queryClient, path, method, listPath, operationsRegistry
|
|
17
|
+
* @param pathParams Path parameters (reactive). Pass `undefined` for operations without path params.
|
|
18
|
+
* @param options Mutation options (dontInvalidate, refetchEndpoints, etc.)
|
|
34
19
|
*/
|
|
35
|
-
export function useEndpointMutation(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (!h.isMutationOperation(operationId)) {
|
|
39
|
-
const { method } = h.getOperationInfo(operationId);
|
|
40
|
-
throw new Error(`Operation '${String(operationId)}' uses method ${method} and cannot be used with useMutation(). ` +
|
|
20
|
+
export function useEndpointMutation(config, pathParams, options) {
|
|
21
|
+
if (!isMutationMethod(config.method)) {
|
|
22
|
+
throw new Error(`Operation at '${config.path}' uses method ${config.method} and cannot be used with useMutation(). ` +
|
|
41
23
|
`Use useQuery() for GET/HEAD/OPTIONS operations.`);
|
|
42
24
|
}
|
|
43
|
-
const { path, method } = h.getOperationInfo(operationId);
|
|
44
25
|
const { pathParams: resolvedPathParamsInput, options: resolvedOptions } = normalizeParamsOptions(pathParams, options);
|
|
45
26
|
const { axiosOptions, dontInvalidate, dontUpdateCache, invalidateOperations, refetchEndpoints, queryParams, ...useMutationOptions } = resolvedOptions;
|
|
46
27
|
const extraPathParams = ref({});
|
|
47
|
-
|
|
48
|
-
const { resolvedPath, queryKey, queryParams: resolvedQueryParams, pathParams: allPathParams, } = useResolvedOperation(path, resolvedPathParamsInput, queryParams, extraPathParams);
|
|
28
|
+
const { resolvedPath, queryKey, queryParams: resolvedQueryParams, pathParams: allPathParams, } = useResolvedOperation(config.path, resolvedPathParamsInput, queryParams, extraPathParams);
|
|
49
29
|
const mutation = useMutation({
|
|
50
30
|
mutationFn: async (vars) => {
|
|
51
|
-
const {
|
|
52
|
-
|
|
53
|
-
|
|
31
|
+
const { pathParams: pathParamsFromMutate, axiosOptions: axiosOptionsFromMutate, queryParams: queryParamsFromMutate, } = (vars || {});
|
|
32
|
+
const data = vars?.data;
|
|
33
|
+
extraPathParams.value = (pathParamsFromMutate || {});
|
|
54
34
|
if (!isPathResolved(resolvedPath.value)) {
|
|
55
|
-
return Promise.reject(new Error(`Cannot execute mutation '${
|
|
35
|
+
return Promise.reject(new Error(`Cannot execute mutation at '${config.path}': path parameters not resolved. ` +
|
|
56
36
|
`Path: '${resolvedPath.value}', provided params: ${JSON.stringify(allPathParams.value)}`));
|
|
57
37
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
method: method.toLowerCase(),
|
|
38
|
+
await config.queryClient.cancelQueries({ queryKey: queryKey.value, exact: false });
|
|
39
|
+
return config.axios({
|
|
40
|
+
method: config.method.toLowerCase(),
|
|
62
41
|
url: resolvedPath.value,
|
|
63
42
|
...(data !== undefined && { data }),
|
|
64
43
|
...axiosOptions,
|
|
@@ -70,43 +49,34 @@ pathParams, options) {
|
|
|
70
49
|
},
|
|
71
50
|
});
|
|
72
51
|
},
|
|
73
|
-
onSuccess: async (response, vars
|
|
52
|
+
onSuccess: async (response, vars) => {
|
|
74
53
|
const data = response.data;
|
|
75
|
-
const { dontInvalidate: dontInvalidateMutate, dontUpdateCache: dontUpdateCacheMutate, invalidateOperations: invalidateOperationsMutate, refetchEndpoints: refetchEndpointsMutate, } = vars || {};
|
|
76
|
-
//
|
|
77
|
-
if (
|
|
78
|
-
// dontUpdateCacheMutate supersedes dontUpdateCache from options
|
|
79
|
-
(dontUpdateCacheMutate !== undefined ? !dontUpdateCacheMutate : !dontUpdateCache) &&
|
|
54
|
+
const { dontInvalidate: dontInvalidateMutate, dontUpdateCache: dontUpdateCacheMutate, invalidateOperations: invalidateOperationsMutate, refetchEndpoints: refetchEndpointsMutate, } = (vars || {});
|
|
55
|
+
// Update cache for PUT/PATCH
|
|
56
|
+
if ((dontUpdateCacheMutate !== undefined ? !dontUpdateCacheMutate : !dontUpdateCache) &&
|
|
80
57
|
data &&
|
|
81
|
-
[HttpMethod.PUT, HttpMethod.PATCH].includes(method)) {
|
|
82
|
-
await
|
|
58
|
+
[HttpMethod.PUT, HttpMethod.PATCH].includes(config.method)) {
|
|
59
|
+
await config.queryClient.setQueryData(queryKey.value, data);
|
|
83
60
|
}
|
|
84
|
-
// Invalidate queries for this path
|
|
61
|
+
// Invalidate queries for this path
|
|
85
62
|
if (dontInvalidateMutate !== undefined ? !dontInvalidateMutate : !dontInvalidate) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
63
|
+
await config.queryClient.invalidateQueries({
|
|
64
|
+
queryKey: queryKey.value,
|
|
65
|
+
exact: config.method !== HttpMethod.POST,
|
|
66
|
+
});
|
|
67
|
+
// Invalidate associated list path
|
|
68
|
+
if (config.listPath) {
|
|
69
|
+
const listResolvedPath = resolvePath(config.listPath, resolvedPathParamsInput);
|
|
91
70
|
if (isPathResolved(listResolvedPath)) {
|
|
92
71
|
const listQueryKey = generateQueryKey(listResolvedPath);
|
|
93
|
-
|
|
94
|
-
// For queries with query parameters (objects), strip the last element before comparing.
|
|
95
|
-
// This matches:
|
|
96
|
-
// - List queries without params: ["api", "user"]
|
|
97
|
-
// - List queries with params: ["api", "user", {filter}] → normalized to ["api", "user"]
|
|
98
|
-
// But NOT single-item queries where last element is a primitive:
|
|
99
|
-
// - Single-item: ["api", "user", "uuid"] → kept as ["api", "user", "uuid"]
|
|
100
|
-
await h.queryClient.invalidateQueries({
|
|
72
|
+
await config.queryClient.invalidateQueries({
|
|
101
73
|
predicate: (query) => {
|
|
102
74
|
const qKey = query.queryKey;
|
|
103
75
|
if (!qKey || qKey.length === 0)
|
|
104
76
|
return false;
|
|
105
|
-
// Normalize query key: strip last element if it's an object (query params)
|
|
106
77
|
const normalizedKey = typeof qKey[qKey.length - 1] === 'object' && qKey[qKey.length - 1] !== null
|
|
107
78
|
? qKey.slice(0, -1)
|
|
108
79
|
: qKey;
|
|
109
|
-
// Compare with listQueryKey
|
|
110
80
|
if (normalizedKey.length !== listQueryKey.length)
|
|
111
81
|
return false;
|
|
112
82
|
for (let i = 0; i < listQueryKey.length; i++) {
|
|
@@ -119,47 +89,61 @@ pathParams, options) {
|
|
|
119
89
|
}
|
|
120
90
|
}
|
|
121
91
|
}
|
|
92
|
+
// Resolve invalidateOperations entries using the registry
|
|
93
|
+
const registry = config.operationsRegistry || {};
|
|
94
|
+
const allInvalidateOps = [invalidateOperations, invalidateOperationsMutate].filter(Boolean);
|
|
122
95
|
const operationsWithPathParams = [];
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
96
|
+
for (const ops of allInvalidateOps) {
|
|
97
|
+
if (!ops)
|
|
98
|
+
continue;
|
|
99
|
+
if (Array.isArray(ops)) {
|
|
100
|
+
operationsWithPathParams.push(...ops.map((id) => [id, {}]));
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
operationsWithPathParams.push(...Object.entries(ops).map(([id, params]) => [id, params]));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
128
106
|
if (operationsWithPathParams.length > 0) {
|
|
129
107
|
const promises = operationsWithPathParams.map(([opId, opParams]) => {
|
|
130
|
-
const opInfo =
|
|
108
|
+
const opInfo = registry[opId];
|
|
109
|
+
if (!opInfo) {
|
|
110
|
+
console.warn(`Cannot invalidate operation '${opId}': not found in operations registry`);
|
|
111
|
+
return Promise.resolve();
|
|
112
|
+
}
|
|
131
113
|
const opPath = resolvePath(opInfo.path, {
|
|
132
114
|
...allPathParams.value,
|
|
133
115
|
...opParams,
|
|
134
116
|
});
|
|
135
117
|
if (isPathResolved(opPath)) {
|
|
136
118
|
const opQueryKey = generateQueryKey(opPath);
|
|
137
|
-
return
|
|
119
|
+
return config.queryClient.invalidateQueries({ queryKey: opQueryKey, exact: true });
|
|
138
120
|
}
|
|
139
121
|
else {
|
|
140
|
-
console.warn(`Cannot invalidate operation '${
|
|
141
|
-
return Promise.
|
|
122
|
+
console.warn(`Cannot invalidate operation '${opId}', path not resolved: ${opPath}`);
|
|
123
|
+
return Promise.resolve();
|
|
142
124
|
}
|
|
143
125
|
});
|
|
144
126
|
await Promise.all(promises);
|
|
145
127
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
128
|
+
const allRefetch = [
|
|
129
|
+
...(refetchEndpoints || []),
|
|
130
|
+
...(vars?.refetchEndpoints || []),
|
|
131
|
+
...(refetchEndpointsMutate || []),
|
|
132
|
+
];
|
|
133
|
+
if (allRefetch.length > 0) {
|
|
134
|
+
await Promise.all(allRefetch.map((ep) => ep.refetch()));
|
|
151
135
|
}
|
|
152
136
|
},
|
|
153
137
|
onSettled: () => {
|
|
154
138
|
extraPathParams.value = {};
|
|
155
139
|
},
|
|
156
140
|
...useMutationOptions,
|
|
157
|
-
},
|
|
141
|
+
}, config.queryClient);
|
|
158
142
|
return {
|
|
159
143
|
...mutation,
|
|
160
144
|
data: mutation.data,
|
|
161
145
|
isEnabled: computed(() => isPathResolved(resolvedPath.value)),
|
|
162
|
-
extraPathParams,
|
|
146
|
+
extraPathParams: extraPathParams,
|
|
163
147
|
pathParams: allPathParams,
|
|
164
148
|
};
|
|
165
149
|
}
|
package/dist/openapi-query.d.ts
CHANGED
|
@@ -1,40 +1,22 @@
|
|
|
1
|
-
import { type ComputedRef, type
|
|
2
|
-
import
|
|
3
|
-
import { type
|
|
1
|
+
import { type ComputedRef, type Ref } from 'vue';
|
|
2
|
+
import type { MaybeRefOrGetter } from '@vue/reactivity';
|
|
3
|
+
import { type EndpointConfig, type QueryOptions } from './types';
|
|
4
4
|
/**
|
|
5
|
-
* Return type of `
|
|
5
|
+
* Return type of `useEndpointQuery` (the `useQuery` composable on a generated namespace).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* All properties are reactive (ComputedRef) and auto-unwrap in Vue templates.
|
|
10
|
-
*
|
|
11
|
-
* @template Ops - The operations type from your OpenAPI specification
|
|
12
|
-
* @template Op - The operation key from your operations type
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```typescript
|
|
16
|
-
* const query = api.useQuery('listPets', { queryParams: { limit: 10 } })
|
|
17
|
-
*
|
|
18
|
-
* // Reactive properties
|
|
19
|
-
* if (query.isPending.value) console.log('Loading...')
|
|
20
|
-
* if (query.isError.value) console.log('Error:', query.error.value)
|
|
21
|
-
* if (query.isSuccess.value) console.log('Data:', query.data.value)
|
|
22
|
-
*
|
|
23
|
-
* // Helpers
|
|
24
|
-
* query.refetch() // Manual refetch
|
|
25
|
-
* query.onLoad((data) => console.log('First load:', data))
|
|
26
|
-
* ```
|
|
7
|
+
* @template TResponse Response data type
|
|
8
|
+
* @template TPathParams Path parameters type (concrete, no undefined)
|
|
27
9
|
*
|
|
28
10
|
* @group Types
|
|
29
11
|
*/
|
|
30
|
-
export interface
|
|
12
|
+
export interface QueryReturn<TResponse, TPathParams extends Record<string, unknown> = Record<string, never>> {
|
|
31
13
|
/** The response data (undefined until loaded). */
|
|
32
|
-
data: ComputedRef<
|
|
14
|
+
data: ComputedRef<TResponse | undefined>;
|
|
33
15
|
/** The error if the query failed. */
|
|
34
16
|
error: Ref<Error | null>;
|
|
35
17
|
/** True while the query is loading. */
|
|
36
18
|
isPending: Ref<boolean>;
|
|
37
|
-
/** True while loading (
|
|
19
|
+
/** True while loading (alias for isPending). */
|
|
38
20
|
isLoading: Ref<boolean>;
|
|
39
21
|
/** True when the query succeeded. */
|
|
40
22
|
isSuccess: Ref<boolean>;
|
|
@@ -44,36 +26,26 @@ export interface EndpointQueryReturn<Ops extends Operations<Ops>, Op extends key
|
|
|
44
26
|
refetch: () => Promise<void>;
|
|
45
27
|
/** Whether the query is currently enabled. */
|
|
46
28
|
isEnabled: ComputedRef<boolean>;
|
|
47
|
-
/** The resolved query key
|
|
29
|
+
/** The resolved query key. */
|
|
48
30
|
queryKey: ComputedRef<string[] | (string | unknown)[]>;
|
|
49
31
|
/** The resolved path parameters. */
|
|
50
|
-
pathParams: ComputedRef<
|
|
32
|
+
pathParams: ComputedRef<TPathParams>;
|
|
51
33
|
/** Register a callback for when data loads successfully for the first time. */
|
|
52
|
-
onLoad: (callback: (data:
|
|
34
|
+
onLoad: (callback: (data: TResponse) => void) => void;
|
|
53
35
|
}
|
|
54
36
|
/**
|
|
55
37
|
* Execute a type-safe query (GET/HEAD/OPTIONS) with automatic caching.
|
|
56
38
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
39
|
+
* This is a low-level primitive — in normal usage it is called by the generated
|
|
40
|
+
* per-operation `useQuery` wrappers in `api-client.ts`, not directly.
|
|
41
|
+
*
|
|
42
|
+
* @template TResponse The response data type
|
|
43
|
+
* @template TPathParams The path parameters type (concrete, required values)
|
|
44
|
+
* @template TQueryParams The query parameters type
|
|
59
45
|
*
|
|
60
|
-
* @
|
|
61
|
-
* @
|
|
62
|
-
* @param
|
|
63
|
-
* @param h - OpenAPI helpers (internal), provided by useOpenApi
|
|
64
|
-
* @param pathParams - Path parameters (can be reactive). Omit for operations without path params.
|
|
65
|
-
* @param options - Query options (enabled, staleTime, queryParams, etc.)
|
|
66
|
-
* - `enabled`: Whether the query should auto-run (boolean or reactive)
|
|
67
|
-
* - `queryParams`: Query string parameters (operation-specific)
|
|
68
|
-
* - `onLoad`: Callback invoked once when data is loaded
|
|
69
|
-
* - `axiosOptions`: Custom axios request options (headers, params, etc.)
|
|
70
|
-
* - Plus all {@link UseQueryOptions} from @tanstack/vue-query
|
|
71
|
-
* @throws Error if the operation is not a query operation
|
|
72
|
-
* @returns Query object with strict typing and helpers:
|
|
73
|
-
* - `data`: ComputedRef of response data
|
|
74
|
-
* - `isEnabled`: ComputedRef indicating if query is enabled
|
|
75
|
-
* - `queryKey`: ComputedRef of the query key
|
|
76
|
-
* - `onLoad(callback)`: Register a callback for when data is loaded
|
|
46
|
+
* @param config Endpoint config: axios instance, queryClient, path, method, listPath
|
|
47
|
+
* @param pathParams Path parameters (reactive). Pass `undefined` for operations without path params.
|
|
48
|
+
* @param options Query options (enabled, staleTime, queryParams, onLoad, etc.)
|
|
77
49
|
*/
|
|
78
|
-
export declare function useEndpointQuery<
|
|
50
|
+
export declare function useEndpointQuery<TResponse, TPathParams extends Record<string, unknown> = Record<string, never>, TQueryParams extends Record<string, unknown> = Record<string, never>>(config: EndpointConfig, pathParams?: MaybeRefOrGetter<Record<string, string | number | undefined> | null | undefined>, options?: QueryOptions<TResponse, TQueryParams>): QueryReturn<TResponse, TPathParams>;
|
|
79
51
|
//# sourceMappingURL=openapi-query.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi-query.d.ts","sourceRoot":"","sources":["../src/openapi-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,WAAW,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"openapi-query.d.ts","sourceRoot":"","sources":["../src/openapi-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,WAAW,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAA;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAIvD,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,YAAY,EAAiB,MAAM,SAAS,CAAA;AAG/E;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW,CAAC,SAAS,EAAE,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;IACzG,kDAAkD;IAClD,IAAI,EAAE,WAAW,CAAC,SAAS,GAAG,SAAS,CAAC,CAAA;IACxC,qCAAqC;IACrC,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAA;IACxB,uCAAuC;IACvC,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IACvB,gDAAgD;IAChD,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IACvB,qCAAqC;IACrC,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IACvB,kCAAkC;IAClC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IACrB,kCAAkC;IAClC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5B,8CAA8C;IAC9C,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;IAC/B,8BAA8B;IAC9B,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,CAAA;IACtD,oCAAoC;IACpC,UAAU,EAAE,WAAW,CAAC,WAAW,CAAC,CAAA;IACpC,+EAA+E;IAC/E,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,KAAK,IAAI,CAAA;CACtD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EACT,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EACnE,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEpE,MAAM,EAAE,cAAc,EACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,EAC7F,OAAO,CAAC,EAAE,YAAY,CAAC,SAAS,EAAE,YAAY,CAAC,GAC9C,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,CAuGrC"}
|
package/dist/openapi-query.js
CHANGED
|
@@ -1,44 +1,30 @@
|
|
|
1
1
|
import { computed, watch, toValue } from 'vue';
|
|
2
2
|
import { useQuery } from '@tanstack/vue-query';
|
|
3
|
-
import { normalizeParamsOptions, useResolvedOperation } from './openapi-utils.js';
|
|
4
3
|
import { isAxiosError } from 'axios';
|
|
4
|
+
import { isQueryMethod } from './types.js';
|
|
5
|
+
import { normalizeParamsOptions, useResolvedOperation } from './openapi-utils.js';
|
|
5
6
|
/**
|
|
6
7
|
* Execute a type-safe query (GET/HEAD/OPTIONS) with automatic caching.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* This is a low-level primitive — in normal usage it is called by the generated
|
|
10
|
+
* per-operation `useQuery` wrappers in `api-client.ts`, not directly.
|
|
11
|
+
*
|
|
12
|
+
* @template TResponse The response data type
|
|
13
|
+
* @template TPathParams The path parameters type (concrete, required values)
|
|
14
|
+
* @template TQueryParams The query parameters type
|
|
10
15
|
*
|
|
11
|
-
* @
|
|
12
|
-
* @
|
|
13
|
-
* @param
|
|
14
|
-
* @param h - OpenAPI helpers (internal), provided by useOpenApi
|
|
15
|
-
* @param pathParams - Path parameters (can be reactive). Omit for operations without path params.
|
|
16
|
-
* @param options - Query options (enabled, staleTime, queryParams, etc.)
|
|
17
|
-
* - `enabled`: Whether the query should auto-run (boolean or reactive)
|
|
18
|
-
* - `queryParams`: Query string parameters (operation-specific)
|
|
19
|
-
* - `onLoad`: Callback invoked once when data is loaded
|
|
20
|
-
* - `axiosOptions`: Custom axios request options (headers, params, etc.)
|
|
21
|
-
* - Plus all {@link UseQueryOptions} from @tanstack/vue-query
|
|
22
|
-
* @throws Error if the operation is not a query operation
|
|
23
|
-
* @returns Query object with strict typing and helpers:
|
|
24
|
-
* - `data`: ComputedRef of response data
|
|
25
|
-
* - `isEnabled`: ComputedRef indicating if query is enabled
|
|
26
|
-
* - `queryKey`: ComputedRef of the query key
|
|
27
|
-
* - `onLoad(callback)`: Register a callback for when data is loaded
|
|
16
|
+
* @param config Endpoint config: axios instance, queryClient, path, method, listPath
|
|
17
|
+
* @param pathParams Path parameters (reactive). Pass `undefined` for operations without path params.
|
|
18
|
+
* @param options Query options (enabled, staleTime, queryParams, onLoad, etc.)
|
|
28
19
|
*/
|
|
29
|
-
export function useEndpointQuery(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const { method } = h.getOperationInfo(operationId);
|
|
33
|
-
throw new Error(`Operation '${String(operationId)}' uses method ${method} and cannot be used with useQuery(). ` +
|
|
20
|
+
export function useEndpointQuery(config, pathParams, options) {
|
|
21
|
+
if (!isQueryMethod(config.method)) {
|
|
22
|
+
throw new Error(`Operation at '${config.path}' uses method ${config.method} and cannot be used with useQuery(). ` +
|
|
34
23
|
`Use useMutation() for POST/PUT/PATCH/DELETE operations.`);
|
|
35
24
|
}
|
|
36
|
-
const { path, method } = h.getOperationInfo(operationId);
|
|
37
25
|
const { pathParams: resolvedPathParamsInput, options: resolvedOptions } = normalizeParamsOptions(pathParams, options);
|
|
38
26
|
const { enabled: enabledInit, onLoad: onLoadInit, axiosOptions, errorHandler, queryParams, ...useQueryOptions } = resolvedOptions;
|
|
39
|
-
|
|
40
|
-
const { resolvedPath, queryKey, isResolved, queryParams: resolvedQueryParams, pathParams: resolvedPathParams, } = useResolvedOperation(path, resolvedPathParamsInput, queryParams);
|
|
41
|
-
// Check if path is fully resolved for enabling the query
|
|
27
|
+
const { resolvedPath, queryKey, isResolved, queryParams: resolvedQueryParams, pathParams: resolvedPathParams, } = useResolvedOperation(config.path, resolvedPathParamsInput, queryParams);
|
|
42
28
|
const isEnabled = computed(() => {
|
|
43
29
|
const baseEnabled = enabledInit !== undefined ? toValue(enabledInit) : true;
|
|
44
30
|
return baseEnabled && isResolved.value;
|
|
@@ -47,8 +33,8 @@ export function useEndpointQuery(operationId, h, pathParams, options) {
|
|
|
47
33
|
queryKey: queryKey,
|
|
48
34
|
queryFn: async () => {
|
|
49
35
|
try {
|
|
50
|
-
const response = await
|
|
51
|
-
method: method.toLowerCase(),
|
|
36
|
+
const response = await config.axios({
|
|
37
|
+
method: config.method.toLowerCase(),
|
|
52
38
|
url: resolvedPath.value,
|
|
53
39
|
...axiosOptions,
|
|
54
40
|
params: {
|
|
@@ -61,67 +47,48 @@ export function useEndpointQuery(operationId, h, pathParams, options) {
|
|
|
61
47
|
catch (error) {
|
|
62
48
|
if (errorHandler && isAxiosError(error)) {
|
|
63
49
|
const result = await errorHandler(error);
|
|
64
|
-
if (result !== undefined)
|
|
50
|
+
if (result !== undefined)
|
|
65
51
|
return result;
|
|
66
|
-
}
|
|
67
|
-
// If errorHandler returns undefined and doesn't throw,
|
|
68
|
-
// we consider this a "recovered" state and return undefined
|
|
69
|
-
// TanStack Query will handle this as a successful query with no data
|
|
70
52
|
return undefined;
|
|
71
53
|
}
|
|
72
|
-
|
|
73
|
-
throw error;
|
|
74
|
-
}
|
|
54
|
+
throw error;
|
|
75
55
|
}
|
|
76
56
|
},
|
|
77
57
|
enabled: isEnabled,
|
|
78
58
|
staleTime: 1000 * 60,
|
|
79
59
|
retry: (_failureCount, error) => {
|
|
80
|
-
// Don't retry 4xx errors if error is AxiosError
|
|
81
60
|
if (isAxiosError(error) && error.response && error.response.status >= 400 && error.response.status < 500) {
|
|
82
61
|
return false;
|
|
83
62
|
}
|
|
84
|
-
// Retry up to 3 times for other errors
|
|
85
63
|
return _failureCount < 3;
|
|
86
64
|
},
|
|
87
65
|
...useQueryOptions,
|
|
88
66
|
};
|
|
89
|
-
const query = useQuery(queryOptions,
|
|
90
|
-
// onLoad callback management using a Set for efficient tracking
|
|
67
|
+
const query = useQuery(queryOptions, config.queryClient);
|
|
91
68
|
const onLoadCallbacks = new Set();
|
|
92
|
-
|
|
93
|
-
if (onLoadInit) {
|
|
69
|
+
if (onLoadInit)
|
|
94
70
|
onLoadCallbacks.add(onLoadInit);
|
|
95
|
-
}
|
|
96
|
-
// Single watch instance to handle all callbacks - stop after first successful data
|
|
97
71
|
if (query.data.value !== undefined) {
|
|
98
|
-
// Data already available - call all callbacks immediately
|
|
99
72
|
onLoadCallbacks.forEach((cb) => cb(query.data.value));
|
|
100
73
|
onLoadCallbacks.clear();
|
|
101
74
|
}
|
|
102
75
|
else {
|
|
103
|
-
// Watch for data to become available - stop after first successful load
|
|
104
76
|
const stopWatch = watch(query.data, (newData) => {
|
|
105
77
|
if (newData !== undefined && onLoadCallbacks.size > 0) {
|
|
106
|
-
// Call all pending callbacks
|
|
107
78
|
onLoadCallbacks.forEach((cb) => cb(newData));
|
|
108
79
|
onLoadCallbacks.clear();
|
|
109
|
-
stopWatch();
|
|
80
|
+
stopWatch();
|
|
110
81
|
}
|
|
111
82
|
});
|
|
112
83
|
}
|
|
113
|
-
// Public onLoad method to register additional callbacks
|
|
114
84
|
const onLoad = (callback) => {
|
|
115
85
|
if (query.data.value !== undefined) {
|
|
116
|
-
// Data already available - call immediately
|
|
117
86
|
callback(query.data.value);
|
|
118
87
|
}
|
|
119
88
|
else {
|
|
120
|
-
// Add to pending callbacks
|
|
121
89
|
onLoadCallbacks.add(callback);
|
|
122
90
|
}
|
|
123
91
|
};
|
|
124
|
-
// Return object spread with data wrapped as ComputedRef for Vue template unwrapping
|
|
125
92
|
return {
|
|
126
93
|
...query,
|
|
127
94
|
data: computed(() => query.data.value),
|
package/dist/openapi-utils.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type ComputedRef
|
|
1
|
+
import { type ComputedRef } from 'vue';
|
|
2
|
+
import type { MaybeRefOrGetter } from '@vue/reactivity';
|
|
2
3
|
export declare function resolvePath(path: string, pathParams?: MaybeRefOrGetter<Record<string, string | number | undefined> | null | undefined>): string;
|
|
3
4
|
export declare function isPathResolved(path: string): boolean;
|
|
4
5
|
export declare function generateQueryKey(resolvedPath: string): string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi-utils.d.ts","sourceRoot":"","sources":["../src/openapi-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"openapi-utils.d.ts","sourceRoot":"","sources":["../src/openapi-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,KAAK,CAAA;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAGvD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,GAC5F,MAAM,CAaR;AAGD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAGD,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CAE/D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,UAAU,EAAE,WAAW;IACxD,+DAA+D;IAC/D,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC,CAAA;IACnC,yDAAyD;IACzD,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACjC,gEAAgE;IAChE,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAA;IACrC,4CAA4C;IAC5C,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAA;IAC1D,+DAA+D;IAC/D,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;CACjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EACtF,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAEnE,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,gBAAgB,CAAC,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC,EAC3D,WAAW,CAAC,EAAE,gBAAgB,CAAC,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC,EAC9D,eAAe,CAAC,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;CAAE,GAC/C,iBAAiB,CAAC,UAAU,EAAE,WAAW,CAAC,CAuC5C;AAED,wBAAgB,sBAAsB,CAAC,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EACxF,UAAU,CAAC,EAAE,gBAAgB,CAAC,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC,EAC5D,OAAO,CAAC,EAAE,OAAO,GAChB;IACD,UAAU,EAAE,gBAAgB,CAAC,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;IAC3D,OAAO,EAAE,OAAO,CAAA;CACjB,CAKA"}
|