@qualisero/openapi-endpoint 0.12.3 → 0.13.2

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/types.d.ts CHANGED
@@ -1,49 +1,58 @@
1
1
  import { type AxiosInstance, type AxiosError, type AxiosRequestConfig, type AxiosResponse } from 'axios';
2
- import { UseMutationOptions, type UseQueryOptions } from '@tanstack/vue-query';
3
- import type { MaybeRef, MaybeRefOrGetter } from 'vue';
2
+ import type { MutationObserverOptions, QueryKey, QueryObserverOptions } from '@tanstack/query-core';
3
+ import type { ComputedRef, Ref } from 'vue';
4
4
  import type { EndpointQueryReturn } from './openapi-query';
5
5
  import type { EndpointMutationReturn } from './openapi-mutation';
6
6
  /**
7
7
  * Extended Axios request configuration that allows custom properties.
8
- *
9
- * This type extends the standard AxiosRequestConfig to support custom properties
10
- * that users might add through module augmentation. It ensures compatibility with
11
- * both standard axios options and user-defined custom properties.
12
8
  */
13
9
  export type AxiosRequestConfigExtended = AxiosRequestConfig & Record<string, unknown>;
10
+ /**
11
+ * Error type shown when an operation requires path parameters but they weren't provided.
12
+ *
13
+ * @internal
14
+ */
15
+ export type RequiresPathParameters<Op extends string> = {
16
+ readonly __error: `Operation '${Op}' requires path parameters as the second argument`;
17
+ readonly __fix: 'Provide path parameters as the second argument';
18
+ readonly __see: 'Check the operation path definition (e.g., /pets/{petId}) or JSDoc';
19
+ };
20
+ /**
21
+ * Validates that path parameters have no excess properties.
22
+ *
23
+ * @internal
24
+ */
25
+ export type HasExcessPathParams<Provided extends Record<string, unknown>, Expected extends Record<string, unknown>> = Exclude<keyof Provided, keyof Expected> extends never ? true : false;
26
+ /**
27
+ * Type representing an operation that does NOT require path parameters.
28
+ * Used in function signatures to restrict which operations can be called without path params.
29
+ *
30
+ * @internal
31
+ */
32
+ export type NoPathParams<Ops extends Operations<Ops>, Op extends keyof Ops> = Op & (ApiPathParams<Ops, Op> extends Record<string, never> ? Op : RequiresPathParameters<Op & string>);
33
+ /**
34
+ * Type representing an operation that DOES require path parameters.
35
+ * Used in function signatures to restrict which operations must be called with path params.
36
+ *
37
+ * @internal
38
+ */
39
+ export type WithPathParams<Ops extends Operations<Ops>, Op extends keyof Ops> = Op & (ApiPathParams<Ops, Op> extends Record<string, never> ? RequiresPathParameters<Op & string> : Op);
14
40
  /** @internal */
15
41
  export type { EndpointQueryReturn, EndpointMutationReturn };
16
- export type OperationId = string;
17
42
  /**
18
43
  * Interface defining the minimal QueryClient methods required by this library.
19
44
  *
20
45
  * This interface ensures compatibility with different versions of @tanstack/vue-query
21
46
  * by only requiring the specific methods that are actually used internally.
22
- * This prevents version compatibility issues where internal implementation details
23
- * (like private properties) might differ between versions.
24
47
  *
25
48
  * @group Types
26
49
  */
27
50
  export interface QueryClientLike {
28
- /**
29
- * Cancel running queries that match the provided filters.
30
- * Used to prevent race conditions when mutations affect data.
31
- */
32
51
  cancelQueries(filters: {
33
52
  queryKey: unknown[];
34
53
  exact?: boolean;
35
54
  }): Promise<void>;
36
- /**
37
- * Set query data for a specific query key.
38
- * Used for optimistic updates after successful mutations.
39
- */
40
55
  setQueryData(queryKey: unknown[], data: unknown): void;
41
- /**
42
- * Invalidate queries that match the provided filters.
43
- * Used to trigger refetches of related data after mutations.
44
- *
45
- * @param filters - Filters can include queryKey, exact, and/or a predicate function
46
- */
47
56
  invalidateQueries(filters: {
48
57
  queryKey?: unknown[];
49
58
  exact?: boolean;
@@ -52,64 +61,34 @@ export interface QueryClientLike {
52
61
  }) => boolean;
53
62
  }): Promise<void>;
54
63
  }
64
+ /** @internal */
55
65
  export type Operations<Ops> = object & {
56
- [K in keyof Ops]: {
57
- method: HttpMethod;
58
- };
66
+ [K in keyof Ops]: OperationInfo;
59
67
  };
60
68
  /**
61
69
  * Configuration object for initializing the OpenAPI client.
62
70
  *
63
- * This interface defines the required configuration to set up a type-safe OpenAPI client
64
- * with Vue Query integration. It requires both the operations metadata (typically generated
65
- * from your OpenAPI specification) and an Axios instance for making HTTP requests.
66
- *
67
71
  * @template Ops - The operations type, typically generated from your OpenAPI specification
68
- * @template AxiosConfig - The axios request configuration type (defaults to AxiosRequestConfig)
69
72
  *
70
73
  * @example
71
74
  * ```typescript
72
- * import { OpenApiConfig } from '@qualisero/openapi-endpoint'
75
+ * import { useOpenApi } from '@qualisero/openapi-endpoint'
73
76
  * import { openApiOperations, type OpenApiOperations } from './generated/api-operations'
74
77
  * import axios from 'axios'
75
78
  *
76
- * // Basic usage with default axios config
77
79
  * const config: OpenApiConfig<OpenApiOperations> = {
78
80
  * operations: openApiOperations,
79
- * axios: axios.create({
80
- * baseURL: 'https://api.example.com',
81
- * headers: { 'Authorization': 'Bearer token' }
82
- * }),
81
+ * axios: axios.create({ baseURL: 'https://api.example.com' }),
83
82
  * queryClient: customQueryClient // optional
84
83
  * }
85
- *
86
- * // With custom axios config type (for module augmentation)
87
- * const configWithCustomAxios: OpenApiConfig<OpenApiOperations, MyCustomAxiosRequestConfig> = {
88
- * operations: openApiOperations,
89
- * axios: customAxiosInstance
90
- * }
91
84
  * ```
92
85
  */
93
86
  export interface OpenApiConfig<Ops extends Operations<Ops>> {
94
- /**
95
- * The operations metadata object, typically generated from your OpenAPI specification.
96
- * This contains type information and HTTP method details for each API endpoint.
97
- */
98
87
  operations: Ops;
99
- /**
100
- * Axios instance for making HTTP requests.
101
- * Configure this with your base URL, authentication, and any global request/response interceptors.
102
- */
103
88
  axios: AxiosInstance;
104
- /**
105
- * Optional TanStack Query client instance.
106
- * If not provided, a default QueryClient with sensible defaults will be used.
107
- *
108
- * Note: This accepts any QueryClient-like object that implements the required methods,
109
- * ensuring compatibility across different versions of @tanstack/vue-query.
110
- */
111
89
  queryClient?: QueryClientLike;
112
90
  }
91
+ /** @internal */
113
92
  export declare enum HttpMethod {
114
93
  GET = "GET",
115
94
  POST = "POST",
@@ -120,13 +99,43 @@ export declare enum HttpMethod {
120
99
  OPTIONS = "OPTIONS",
121
100
  TRACE = "TRACE"
122
101
  }
102
+ /**
103
+ * HTTP methods that are considered read-only query operations.
104
+ * These can be used with useQuery() and support caching.
105
+ */
106
+ export declare const QUERY_METHODS: readonly [HttpMethod.GET, HttpMethod.HEAD, HttpMethod.OPTIONS];
107
+ /**
108
+ * HTTP methods that modify data and should use mutations.
109
+ */
110
+ export declare const MUTATION_METHODS: readonly [HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH, HttpMethod.DELETE];
111
+ /** @internal */
112
+ export declare function isQueryMethod(method: HttpMethod): boolean;
113
+ /** @internal */
114
+ export declare function isMutationMethod(method: HttpMethod): boolean;
123
115
  /** @internal */
124
116
  export interface OperationInfo {
125
117
  path: string;
126
118
  method: HttpMethod;
127
119
  }
120
+ /** @internal */
128
121
  export type GetOperation<Ops extends Operations<Ops>, Op extends keyof Ops> = Ops[Op];
129
- export type GetResponseData<Ops extends Operations<Ops>, Op extends keyof Ops> = GetOperation<Ops, Op> extends {
122
+ type RequireAll<T> = {
123
+ [K in keyof T]-?: T[K];
124
+ };
125
+ type RequireReadonly<T> = {
126
+ [K in keyof T as IsReadonly<T, K> extends true ? K : never]-?: T[K];
127
+ } & {
128
+ [K in keyof T as IsReadonly<T, K> extends false ? K : never]: T[K];
129
+ };
130
+ type IfEquals<X, Y, A = X, B = never> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B;
131
+ type IsReadonly<T, K extends keyof T> = IfEquals<Pick<T, K>, {
132
+ -readonly [Q in K]: T[K];
133
+ }, false, true>;
134
+ /**
135
+ * Extract the raw response data type from an operation without modifications.
136
+ * @internal
137
+ */
138
+ type ExtractResponseData<Ops extends Operations<Ops>, Op extends keyof Ops> = GetOperation<Ops, Op> extends {
130
139
  responses: {
131
140
  200: {
132
141
  content: {
@@ -134,58 +143,109 @@ export type GetResponseData<Ops extends Operations<Ops>, Op extends keyof Ops> =
134
143
  };
135
144
  };
136
145
  };
137
- } ? RequireReadonly<Data> : unknown;
138
- type OmitMaybeRef<T, K extends PropertyKey> = T extends MaybeRef<infer U> ? MaybeRef<Omit<U, K> & Partial<Pick<U, K & keyof U>>> : Omit<T, K> & Partial<Pick<T, K & keyof T>>;
139
- /** @internal */
140
- export type QQueryOptions<Ops extends Operations<Ops>, Op extends keyof Ops> = OmitMaybeRef<UseQueryOptions<GetResponseData<Ops, Op>, Error, GetResponseData<Ops, Op>, GetResponseData<Ops, Op>>, 'queryKey' | 'queryFn' | 'enabled'> & {
141
- enabled?: MaybeRefOrGetter<boolean>;
142
- onLoad?: (data: GetResponseData<Ops, Op>) => void;
143
- axiosOptions?: AxiosRequestConfigExtended;
144
- errorHandler?: (error: AxiosError) => GetResponseData<Ops, Op> | void | Promise<GetResponseData<Ops, Op> | void>;
145
- queryParams?: MaybeRefOrGetter<GetQueryParameters<Ops, Op>>;
146
- };
147
- type MutationOnSuccessOptions<Ops extends Operations<Ops>> = {
148
- dontInvalidate?: boolean;
149
- dontUpdateCache?: boolean;
150
- invalidateOperations?: (keyof Ops)[] | Partial<{
151
- [K in keyof Ops]: GetPathParameters<Ops, K>;
152
- }>;
153
- refetchEndpoints?: EndpointQueryReturn<Ops, keyof Ops>[];
154
- };
146
+ } ? Data : unknown;
147
+ /**
148
+ * Extract response data type from an operation (all fields required).
149
+ *
150
+ * All fields are REQUIRED regardless of their `required` status in the OpenAPI schema.
151
+ * This assumes the server always returns complete objects.
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * type PetResponse = ApiResponse<OpenApiOperations, 'getPet'>
156
+ * // { readonly id: string, name: string, ... } - all required
157
+ * ```
158
+ */
159
+ export type ApiResponse<Ops extends Operations<Ops>, Op extends keyof Ops> = RequireAll<ExtractResponseData<Ops, Op>>;
160
+ /**
161
+ * Extract response data type with safe typing for unreliable backends.
162
+ *
163
+ * Only readonly properties are REQUIRED. Other properties preserve their optional status.
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * type PetResponse = ApiResponseSafe<OpenApiOperations, 'getPet'>
168
+ * // { readonly id: string, name?: string, ... } - only readonly required
169
+ * ```
170
+ */
171
+ export type ApiResponseSafe<Ops extends Operations<Ops>, Op extends keyof Ops> = RequireReadonly<ExtractResponseData<Ops, Op>>;
172
+ /**
173
+ * A value that can be reactive (ref, computed) or direct.
174
+ * Standardized pattern for all reactive values across the library.
175
+ *
176
+ * @internal
177
+ */
178
+ export type ReactiveOr<T> = T | Ref<T> | ComputedRef<T> | (() => T);
179
+ /**
180
+ * Reactive value that excludes function getters.
181
+ * Useful for path params where function overloads have stricter checks.
182
+ *
183
+ * @internal
184
+ */
185
+ export type ReactiveValue<T> = T | Ref<T> | ComputedRef<T>;
155
186
  /** @internal */
156
- export type QMutationVars<Ops extends Operations<Ops>, Op extends keyof Ops> = MutationOnSuccessOptions<Ops> & {
157
- data?: GetRequestBody<Ops, Op>;
158
- pathParams?: GetPathParameters<Ops, Op>;
159
- axiosOptions?: AxiosRequestConfigExtended;
160
- queryParams?: GetQueryParameters<Ops, Op>;
161
- };
187
+ type MaybeRefLeaf<T> = T | Ref<T> | ComputedRef<T>;
188
+ type MaybeRefDeep<T> = T extends (...args: never[]) => unknown ? T : T extends object ? {
189
+ [K in keyof T]: MaybeRefDeep<T[K]>;
190
+ } : MaybeRefLeaf<T>;
162
191
  /** @internal */
163
- export type QMutationOptions<Ops extends Operations<Ops>, Op extends keyof Ops> = OmitMaybeRef<UseMutationOptions<AxiosResponse<GetResponseData<Ops, Op>>, Error, GetRequestBody<Ops, Op> extends never ? QMutationVars<Ops, Op> | void : QMutationVars<Ops, Op>>, 'mutationFn' | 'mutationKey'> & MutationOnSuccessOptions<Ops> & {
164
- axiosOptions?: AxiosRequestConfigExtended;
165
- queryParams?: MaybeRefOrGetter<GetQueryParameters<Ops, Op>>;
192
+ type ShallowOption = {
193
+ shallow?: boolean;
166
194
  };
167
- export type GetPathParameters<Ops extends Operations<Ops>, Op extends keyof Ops> = Ops[Op] extends {
195
+ /**
196
+ * Extract path parameters type from an operation (truly required).
197
+ *
198
+ * All path parameters from the OpenAPI schema are required - they cannot be undefined.
199
+ * This matches the runtime behavior where missing path params cause errors.
200
+ *
201
+ * @example
202
+ * ```typescript
203
+ * type Params = ApiPathParams<OpenApiOperations, 'getPet'>
204
+ * // { petId: string } - all params required
205
+ * ```
206
+ */
207
+ export type ApiPathParams<Ops extends Operations<Ops>, Op extends keyof Ops> = Ops[Op] extends {
168
208
  parameters: {
169
209
  path: infer PathParams;
170
210
  };
171
- } ? {
172
- [K in keyof PathParams]: PathParams[K] | undefined;
173
- } : Record<string, never>;
174
- export type GetQueryParameters<Ops extends Operations<Ops>, Op extends keyof Ops> = Ops[Op] extends {
211
+ } ? PathParams extends Record<string, unknown> ? PathParams : Record<string, never> : Record<string, never>;
212
+ /**
213
+ * Path params input type that allows undefined values for reactive resolution.
214
+ *
215
+ * @internal
216
+ */
217
+ export type ApiPathParamsInput<Ops extends Operations<Ops>, Op extends keyof Ops> = {
218
+ [K in keyof ApiPathParams<Ops, Op>]: ApiPathParams<Ops, Op>[K] | undefined;
219
+ };
220
+ /**
221
+ * Extract query parameters type from an operation.
222
+ * @example
223
+ * ```typescript
224
+ * type Params = ApiQueryParams<OpenApiOperations, 'listPets'>
225
+ * // { limit?: number, status?: string }
226
+ * ```
227
+ */
228
+ export type ApiQueryParams<Ops extends Operations<Ops>, Op extends keyof Ops> = Ops[Op] extends {
175
229
  parameters: {
176
230
  query?: infer QueryParams;
177
231
  };
178
232
  } ? QueryParams extends Record<string, unknown> ? {
179
233
  [K in keyof QueryParams]?: QueryParams[K];
180
234
  } : Record<string, never> : Record<string, never>;
181
- type IfEquals<X, Y, A = X, B = never> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B;
182
- type IsReadonly<T, K extends keyof T> = IfEquals<Pick<T, K>, {
183
- -readonly [Q in K]: T[K];
184
- }, false, true>;
185
235
  type Writable<T> = {
186
- -readonly [K in keyof T as IsReadonly<T, K> extends false ? K : never]: T[K];
236
+ -readonly [K in keyof T as IfEquals<Pick<T, K>, {
237
+ -readonly [Q in K]: T[K];
238
+ }, false, true> extends false ? K : never]: T[K];
187
239
  };
188
- export type GetRequestBody<Ops extends Operations<Ops>, Op extends keyof Ops> = GetOperation<Ops, Op> extends {
240
+ /**
241
+ * Extract request body type from an operation.
242
+ * @example
243
+ * ```typescript
244
+ * type Body = ApiRequest<OpenApiOperations, 'createPet'>
245
+ * // { name: string, species?: string }
246
+ * ```
247
+ */
248
+ export type ApiRequest<Ops extends Operations<Ops>, Op extends keyof Ops> = GetOperation<Ops, Op> extends {
189
249
  requestBody: {
190
250
  content: {
191
251
  'application/json': infer Body;
@@ -198,143 +258,297 @@ export type GetRequestBody<Ops extends Operations<Ops>, Op extends keyof Ops> =
198
258
  };
199
259
  };
200
260
  } ? Writable<Body> | FormData : never;
201
- type RequireReadonly<T> = {
202
- [K in keyof T as IsReadonly<T, K> extends true ? K : never]-?: T[K];
203
- } & {
204
- [K in keyof T as IsReadonly<T, K> extends false ? K : never]: T[K];
205
- };
206
- export type IsQueryOperation<Ops extends Operations<Ops>, Op extends keyof Ops> = Ops[Op] extends {
207
- method: HttpMethod.GET | HttpMethod.HEAD | HttpMethod.OPTIONS;
208
- } ? true : false;
209
261
  /**
210
- * Type representing an instance of the OpenAPI client returned by useOpenApi.
262
+ * Options for controlling automatic cache invalidation and updates after mutations.
211
263
  *
212
- * This interface defines all the methods available on the API client instance,
213
- * providing type-safe access to queries, mutations, and generic endpoints based
214
- * on your OpenAPI specification.
264
+ * By default, mutations automatically:
265
+ * - Update cache for PUT/PATCH responses with the returned data
266
+ * - Invalidate matching GET queries to trigger refetches
215
267
  *
216
268
  * @group Types
217
- * @template Ops - The operations type from your OpenAPI specification
218
- * @template AxiosConfig - The axios request configuration type (defaults to AxiosRequestConfig)
219
- *
220
- * @example
221
- * ```typescript
222
- * import { OpenApiInstance } from '@qualisero/openapi-endpoint'
223
- * import { type OpenApiOperations } from './generated/api-operations'
224
- *
225
- * // Type your API instance for better IntelliSense
226
- * const api: OpenApiInstance<OpenApiOperations> = useOpenApi(config)
227
- *
228
- * // All methods are now fully typed
229
- * const query = api.useQuery('getPet', { petId: '123' })
230
- * const mutation = api.useMutation('createPet')
231
- * const endpoint = api.useEndpoint('listPets')
232
- * ```
233
269
  */
234
- export type OpenApiInstance<Ops extends Operations<Ops>> = {
270
+ export interface CacheInvalidationOptions<Ops extends Operations<Ops>> {
271
+ /**
272
+ * Skip automatic cache invalidation after mutation completes.
273
+ *
274
+ * @default false
275
+ */
276
+ dontInvalidate?: boolean;
235
277
  /**
236
- * Debug utility to inspect operation metadata at runtime.
278
+ * Skip automatic cache update for PUT/PATCH responses.
237
279
  *
238
- * This method helps during development to understand how operations are classified
239
- * and can be useful for debugging type inference issues.
280
+ * @default false
281
+ */
282
+ dontUpdateCache?: boolean;
283
+ /**
284
+ * Additional operations to invalidate after mutation succeeds.
240
285
  *
241
- * @param operationId - The operation ID to inspect
242
- * @returns Boolean indicating whether the operation is a query (GET/HEAD/OPTIONS)
286
+ * Can be either:
287
+ * - Array of operation IDs: `['listPets', 'getPetStats']`
288
+ * - Map of operation ID to path params: `{ getPet: { petId: '123' } }`
243
289
  *
244
290
  * @example
245
291
  * ```typescript
246
- * // Check if an operation is a query or mutation
247
- * const isQuery = api._debugIsQueryOperation('getPet') // true for GET
248
- * const isMutation = api._debugIsQueryOperation('createPet') // false for POST
292
+ * // Invalidate list when creating
293
+ * { invalidateOperations: ['listPets'] }
294
+ *
295
+ * // Invalidate specific item
296
+ * { invalidateOperations: { getPet: { petId: '123' } } }
249
297
  * ```
250
298
  */
251
- _debugIsQueryOperation: <Op extends keyof Ops>(operationId: Op) => IsQueryOperation<Ops, Op>;
299
+ invalidateOperations?: (keyof Ops)[] | Partial<{
300
+ [K in keyof Ops]: ApiPathParams<Ops, K>;
301
+ }>;
252
302
  /**
253
- * Creates a reactive query for GET/HEAD/OPTIONS operations.
303
+ * Specific query endpoints to refetch after mutation succeeds.
254
304
  *
255
- * This method creates a TanStack Query with automatic type inference, caching,
256
- * and reactive updates. Only accepts operation IDs that correspond to query operations.
257
- *
258
- * @template Op - The operation key from your operations type
259
- * @param operationId - Operation ID (must be a GET/HEAD/OPTIONS operation)
260
- * @param pathParamsOrOptions - Path parameters (for parameterized routes) or query options
261
- * @param optionsOrNull - Additional query options when path parameters are provided separately
262
- * @returns Reactive query result with data, loading state, error handling, etc.
305
+ * Use when you have specific query results that need to be refetched.
263
306
  *
264
307
  * @example
265
308
  * ```typescript
266
- * // Simple query without parameters
267
- * const { data: pets, isLoading } = api.useQuery('listPets')
268
- *
269
- * // Query with path parameters
270
- * const { data: pet } = api.useQuery('getPet', { petId: '123' })
271
- *
272
- * // Query with options
273
- * const { data: pets } = api.useQuery('listPets', {
274
- * enabled: computed(() => shouldLoad.value),
275
- * onLoad: (data) => console.log('Loaded:', data)
276
- * })
309
+ * const listQuery = api.useQuery('listPets')
310
+ * { refetchEndpoints: [listQuery] }
277
311
  * ```
278
312
  */
279
- useQuery: <Op extends keyof Ops>(operationId: IsQueryOperation<Ops, Op> extends true ? Op : never, pathParamsOrOptions?: GetPathParameters<Ops, Op> extends Record<string, never> ? QQueryOptions<Ops, Op> : MaybeRefOrGetter<GetPathParameters<Ops, Op> | null | undefined> | QQueryOptions<Ops, Op>, optionsOrNull?: QQueryOptions<Ops, Op>) => EndpointQueryReturn<Ops, Op>;
313
+ refetchEndpoints?: EndpointQueryReturn<Ops, keyof Ops>[];
314
+ }
315
+ /**
316
+ * Query options for `useQuery` with custom extensions.
317
+ *
318
+ * Supports all TanStack Query options plus:
319
+ * - `enabled`: Reactive boolean to control when query runs
320
+ * - `queryParams`: Reactive query string parameters
321
+ * - `onLoad`: Callback when data loads successfully
322
+ * - `errorHandler`: Custom error handler with fallback support
323
+ * - `axiosOptions`: Additional axios configuration
324
+ *
325
+ * @template Ops - The operations type from your OpenAPI specification
326
+ * @template Op - The operation key
327
+ *
328
+ * @example
329
+ * ```typescript
330
+ * const { data } = api.useQuery('listPets', {
331
+ * queryParams: { limit: 10 },
332
+ * enabled: computed(() => isLoggedIn.value),
333
+ * staleTime: 5000,
334
+ * onLoad: (data) => console.log('Loaded:', data.length)
335
+ * })
336
+ * ```
337
+ *
338
+ * @group Types
339
+ */
340
+ type BaseQueryOptions<Ops extends Operations<Ops>, Op extends keyof Ops> = MaybeRefDeep<QueryObserverOptions<ApiResponse<Ops, Op>, Error, ApiResponse<Ops, Op>, ApiResponse<Ops, Op>, QueryKey>> & ShallowOption;
341
+ export type QQueryOptions<Ops extends Operations<Ops>, Op extends keyof Ops> = Omit<BaseQueryOptions<Ops, Op>, 'queryKey' | 'queryFn' | 'enabled'> & {
342
+ /** Whether the query should execute. Can be reactive (ref/computed/function). */
343
+ enabled?: ReactiveOr<boolean>;
344
+ /** Callback when data is successfully loaded for the first time. */
345
+ onLoad?: (data: ApiResponse<Ops, Op>) => void;
346
+ /** Additional axios configuration for this request. */
347
+ axiosOptions?: AxiosRequestConfigExtended;
348
+ /** Custom error handler. Return data to use as fallback, or void to use default error. */
349
+ errorHandler?: (error: AxiosError) => ApiResponse<Ops, Op> | void | Promise<ApiResponse<Ops, Op> | void>;
350
+ /** Query parameters for the request. Can be reactive (ref/computed/function). */
351
+ queryParams?: ReactiveOr<ApiQueryParams<Ops, Op>>;
352
+ };
353
+ /**
354
+ * Variables passed to mutation.mutate() or mutation.mutateAsync().
355
+ *
356
+ * Combines cache invalidation options with mutation-specific data:
357
+ * - `data`: Request body (when operation accepts one)
358
+ * - `pathParams`: Path parameters (can override those from useMutation call)
359
+ * - `queryParams`: Query string parameters
360
+ * - `axiosOptions`: Additional axios configuration
361
+ *
362
+ * Plus all cache invalidation options (dontInvalidate, invalidateOperations, etc.)
363
+ *
364
+ * @template Ops - The operations type
365
+ * @template Op - The operation key
366
+ *
367
+ * @example
368
+ * ```typescript
369
+ * const mutation = api.useMutation('createPet')
370
+ * mutation.mutate({
371
+ * data: { name: 'Fluffy' },
372
+ * invalidateOperations: ['listPets']
373
+ * })
374
+ * ```
375
+ *
376
+ * @group Types
377
+ */
378
+ export type QMutationVars<Ops extends Operations<Ops>, Op extends keyof Ops> = CacheInvalidationOptions<Ops> & {
379
+ data?: ApiRequest<Ops, Op>;
380
+ pathParams?: ApiPathParamsInput<Ops, Op>;
381
+ axiosOptions?: AxiosRequestConfigExtended;
382
+ queryParams?: ApiQueryParams<Ops, Op>;
383
+ };
384
+ /**
385
+ * Resolved return type for mutateAsync to avoid showing full operations union in tooltips.
386
+ * @internal
387
+ */
388
+ export type MutateAsyncReturn<Ops extends Operations<Ops>, Op extends keyof Ops> = Promise<AxiosResponse<ApiResponse<Ops, Op>>>;
389
+ /**
390
+ * Function signature for mutation.mutate() - non-blocking mutation execution.
391
+ *
392
+ * Inlined types allow TypeScript to resolve specific operation types in tooltips
393
+ * instead of showing the entire operations union.
394
+ *
395
+ * @group Types
396
+ * @internal
397
+ */
398
+ export type MutateFn<Ops extends Operations<Ops>, Op extends keyof Ops> = (vars?: {
399
+ data?: ApiRequest<Ops, Op>;
400
+ pathParams?: ApiPathParamsInput<Ops, Op>;
401
+ axiosOptions?: AxiosRequestConfigExtended;
402
+ queryParams?: ApiQueryParams<Ops, Op>;
403
+ dontInvalidate?: boolean;
404
+ dontUpdateCache?: boolean;
405
+ invalidateOperations?: (keyof Ops)[];
406
+ refetchEndpoints?: EndpointQueryReturn<Ops, keyof Ops>[];
407
+ }) => void;
408
+ /**
409
+ * Function signature for mutation.mutateAsync() - async mutation execution.
410
+ *
411
+ * Inlined types allow TypeScript to resolve specific operation types in tooltips
412
+ * instead of showing the entire operations union.
413
+ *
414
+ * @group Types
415
+ * @internal
416
+ */
417
+ export type MutateAsyncFn<Ops extends Operations<Ops>, Op extends keyof Ops> = (vars?: {
418
+ data?: ApiRequest<Ops, Op>;
419
+ pathParams?: ApiPathParamsInput<Ops, Op>;
420
+ axiosOptions?: AxiosRequestConfigExtended;
421
+ queryParams?: ApiQueryParams<Ops, Op>;
422
+ dontInvalidate?: boolean;
423
+ dontUpdateCache?: boolean;
424
+ invalidateOperations?: (keyof Ops)[];
425
+ refetchEndpoints?: EndpointQueryReturn<Ops, keyof Ops>[];
426
+ }) => MutateAsyncReturn<Ops, Op>;
427
+ /**
428
+ * Mutation options for `useMutation` with custom extensions.
429
+ *
430
+ * Supports all TanStack Query mutation options plus:
431
+ * - Cache invalidation options (dontInvalidate, invalidateOperations, etc.)
432
+ * - `queryParams`: Reactive query string parameters
433
+ * - `axiosOptions`: Additional axios configuration
434
+ *
435
+ * @template Ops - The operations type
436
+ * @template Op - The operation key
437
+ *
438
+ * @example
439
+ * ```typescript
440
+ * const mutation = api.useMutation('createPet', {
441
+ * onSuccess: () => console.log('Created!'),
442
+ * invalidateOperations: ['listPets']
443
+ * })
444
+ * ```
445
+ *
446
+ * @group Types
447
+ */
448
+ type MutationVarsInput<Ops extends Operations<Ops>, Op extends keyof Ops> = ApiRequest<Ops, Op> extends never ? QMutationVars<Ops, Op> | void : QMutationVars<Ops, Op>;
449
+ type BaseMutationOptions<Ops extends Operations<Ops>, Op extends keyof Ops> = MaybeRefDeep<MutationObserverOptions<AxiosResponse<ApiResponse<Ops, Op>>, Error, MutationVarsInput<Ops, Op>, unknown>> & ShallowOption;
450
+ export type QMutationOptions<Ops extends Operations<Ops>, Op extends keyof Ops> = Omit<BaseMutationOptions<Ops, Op>, 'mutationFn' | 'mutationKey'> & CacheInvalidationOptions<Ops> & {
451
+ axiosOptions?: AxiosRequestConfigExtended;
452
+ queryParams?: ReactiveOr<ApiQueryParams<Ops, Op>>;
453
+ };
454
+ /**
455
+ * Runtime type validator for mutation parameters.
456
+ *
457
+ * This helper is a pass-through function that helps TypeScript narrow parameter types.
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * const mutation = api.useMutation(MutationOperationId.createPet)
462
+ * await mutation.mutateAsync(
463
+ * validateMutationParams(MutationOperationId.createPet, {
464
+ * data: { name: 'Fluffy' }
465
+ * })
466
+ * )
467
+ * ```
468
+ */
469
+ export declare function validateMutationParams<Ops extends Operations<Ops>, Op extends keyof Ops>(_operationId: Op, params: QMutationVars<Ops, Op>): QMutationVars<Ops, Op>;
470
+ /** @internal */
471
+ export type QueryOpsNoPathParams<Ops extends Operations<Ops>> = {
472
+ [Op in keyof Ops]: Ops[Op]['method'] extends HttpMethod.GET | HttpMethod.HEAD | HttpMethod.OPTIONS ? ApiPathParams<Ops, Op> extends Record<string, never> ? Op : never : never;
473
+ }[keyof Ops];
474
+ /** @internal */
475
+ export type QueryOpsWithPathParams<Ops extends Operations<Ops>> = {
476
+ [Op in keyof Ops]: Ops[Op]['method'] extends HttpMethod.GET | HttpMethod.HEAD | HttpMethod.OPTIONS ? ApiPathParams<Ops, Op> extends Record<string, never> ? never : Op : never;
477
+ }[keyof Ops];
478
+ /** @internal */
479
+ export type MutationOpsNoPathParams<Ops extends Operations<Ops>> = {
480
+ [Op in keyof Ops]: Ops[Op]['method'] extends HttpMethod.POST | HttpMethod.PUT | HttpMethod.PATCH | HttpMethod.DELETE ? ApiPathParams<Ops, Op> extends Record<string, never> ? Op : never : never;
481
+ }[keyof Ops];
482
+ /** @internal */
483
+ export type MutationOpsWithPathParams<Ops extends Operations<Ops>> = {
484
+ [Op in keyof Ops]: Ops[Op]['method'] extends HttpMethod.POST | HttpMethod.PUT | HttpMethod.PATCH | HttpMethod.DELETE ? ApiPathParams<Ops, Op> extends Record<string, never> ? never : Op : never;
485
+ }[keyof Ops];
486
+ /**
487
+ * Type representing an instance of the OpenAPI client returned by useOpenApi.
488
+ *
489
+ * This interface defines all the methods available on the API client instance.
490
+ *
491
+ * @group Types
492
+ * @template Ops - The operations type from your OpenAPI specification
493
+ *
494
+ * @example
495
+ * ```typescript
496
+ * import { useOpenApi } from '@qualisero/openapi-endpoint'
497
+ * import { type OpenApiOperations } from './generated/api-operations'
498
+ *
499
+ * const api: OpenApiInstance<OpenApiOperations> = useOpenApi(config)
500
+ * const query = api.useQuery('getPet', { petId: '123' })
501
+ * const mutation = api.useMutation('createPet')
502
+ * ```
503
+ */
504
+ export type OpenApiInstance<Ops extends Operations<Ops>> = {
280
505
  /**
281
- * Creates a reactive mutation for POST/PUT/PATCH/DELETE operations.
282
- *
283
- * This method creates a TanStack Query mutation with automatic cache invalidation,
284
- * optimistic updates, and type-safe request/response handling. Only accepts operation IDs
285
- * that correspond to mutation operations.
506
+ * Execute a type-safe query (GET/HEAD/OPTIONS) with automatic caching.
286
507
  *
287
- * @template Op - The operation key from your operations type
288
- * @param operationId - Operation ID (must be a POST/PUT/PATCH/DELETE operation)
289
- * @param pathParamsOrOptions - Path parameters (for parameterized routes) or mutation options
290
- * @param optionsOrNull - Additional mutation options when path parameters are provided separately
291
- * @returns Reactive mutation result with mutate, mutateAsync, status, etc.
508
+ * @template Op - The operation key
509
+ * @param operationId - Query operation ID
510
+ * @param pathParams - Path params for operations that require them
511
+ * @param options - Query options
512
+ * @returns Reactive query result
292
513
  *
293
514
  * @example
294
515
  * ```typescript
295
- * // Simple mutation without path parameters
296
- * const createPet = api.useMutation('createPet', {
297
- * onSuccess: (data) => console.log('Created:', data),
298
- * onError: (error) => console.error('Failed:', error)
299
- * })
516
+ * // No path params
517
+ * const listQuery = api.useQuery('listPets', { queryParams: { limit: 10 } })
300
518
  *
301
- * // Mutation with path parameters
302
- * const updatePet = api.useMutation('updatePet', { petId: '123' })
519
+ * // With path params (direct object)
520
+ * const petQuery = api.useQuery('getPet', { petId: '123' })
303
521
  *
304
- * // Execute mutations
305
- * await createPet.mutateAsync({ data: { name: 'Fluffy', species: 'cat' } })
306
- * await updatePet.mutateAsync({ data: { name: 'Updated Name' } })
522
+ * // With path params (reactive function)
523
+ * const id = ref('')
524
+ * const detailsQuery = api.useQuery('getPet', () => ({ petId: id.value }))
307
525
  * ```
308
526
  */
309
- useMutation: <Op extends keyof Ops>(operationId: IsQueryOperation<Ops, Op> extends false ? Op : never, pathParamsOrOptions?: GetPathParameters<Ops, Op> extends Record<string, never> ? QMutationOptions<Ops, Op> : MaybeRefOrGetter<GetPathParameters<Ops, Op> | null | undefined> | QMutationOptions<Ops, Op>, optionsOrNull?: QMutationOptions<Ops, Op>) => EndpointMutationReturn<Ops, Op>;
527
+ useQuery: (<Op extends QueryOpsNoPathParams<Ops>>(operationId: Op, options?: QQueryOptions<Ops, Op>) => EndpointQueryReturn<Ops, Op>) & (<Op extends QueryOpsWithPathParams<Ops>>(operationId: Op, pathParams: ReactiveValue<ApiPathParamsInput<Ops, Op>>, options?: QQueryOptions<Ops, Op>) => EndpointQueryReturn<Ops, Op>) & (<Op extends QueryOpsWithPathParams<Ops>, PathParams extends ApiPathParamsInput<Ops, Op>>(operationId: Op, pathParams: () => PathParams & (HasExcessPathParams<PathParams, ApiPathParams<Ops, Op>> extends true ? PathParams : never), options?: QQueryOptions<Ops, Op>) => EndpointQueryReturn<Ops, Op>);
310
528
  /**
311
- * Generic endpoint composable that automatically detects operation type.
312
- *
313
- * This is a universal method that returns either a query or mutation based on the
314
- * operation's HTTP method. It provides the same functionality as useQuery/useMutation
315
- * but with automatic type detection, making it useful for generic or dynamic scenarios.
529
+ * Execute a type-safe mutation (POST/PUT/PATCH/DELETE) with automatic cache updates.
316
530
  *
317
- * @template Op - The operation key from your operations type
318
- * @param operationId - Any valid operation ID from your API specification
319
- * @param pathParamsOrOptions - Path parameters (for parameterized routes) or operation-specific options
320
- * @param optionsOrNull - Additional options when path parameters are provided separately
321
- * @returns Query result for GET/HEAD/OPTIONS operations, mutation result for others
531
+ * @template Op - The operation key
532
+ * @param operationId - Mutation operation ID
533
+ * @param pathParams - Path params for operations that require them
534
+ * @param options - Mutation options
535
+ * @returns Reactive mutation result
322
536
  *
323
537
  * @example
324
538
  * ```typescript
325
- * // Automatically becomes a query for GET operations
326
- * const listEndpoint = api.useEndpoint('listPets')
327
- * // TypeScript infers this has query properties: .data, .isLoading, .refetch(), etc.
539
+ * // No path params
540
+ * const createPet = api.useMutation('createPet')
541
+ * createPet.mutate({ data: { name: 'Fluffy' } })
328
542
  *
329
- * // Automatically becomes a mutation for POST operations
330
- * const createEndpoint = api.useEndpoint('createPet')
331
- * // TypeScript infers this has mutation properties: .mutate(), .mutateAsync(), etc.
543
+ * // With path params (direct object)
544
+ * const updatePet = api.useMutation('updatePet', { petId: '123' })
545
+ * updatePet.mutate({ data: { name: 'Updated' } })
332
546
  *
333
- * // Use based on the detected type
334
- * const petData = listEndpoint.data // Query data
335
- * await createEndpoint.mutateAsync({ data: { name: 'Fluffy' } }) // Mutation execution
547
+ * // With path params (reactive function)
548
+ * const id = ref('')
549
+ * const deletePet = api.useMutation('deletePet', () => ({ petId: id.value }))
336
550
  * ```
337
551
  */
338
- useEndpoint: <Op extends keyof Ops>(operationId: Op, pathParamsOrOptions?: GetPathParameters<Ops, Op> extends Record<string, never> ? IsQueryOperation<Ops, Op> extends true ? QQueryOptions<Ops, Op> : QMutationOptions<Ops, Op> : MaybeRefOrGetter<GetPathParameters<Ops, Op> | null | undefined> | (IsQueryOperation<Ops, Op> extends true ? QQueryOptions<Ops, Op> : QMutationOptions<Ops, Op>), optionsOrNull?: IsQueryOperation<Ops, Op> extends true ? QQueryOptions<Ops, Op> : QMutationOptions<Ops, Op>) => IsQueryOperation<Ops, Op> extends true ? EndpointQueryReturn<Ops, Op> : EndpointMutationReturn<Ops, Op>;
552
+ useMutation: (<Op extends MutationOpsNoPathParams<Ops>>(operationId: Op, options?: QMutationOptions<Ops, Op>) => EndpointMutationReturn<Ops, Op>) & (<Op extends MutationOpsWithPathParams<Ops>>(operationId: Op, pathParams: ReactiveValue<ApiPathParamsInput<Ops, Op>>, options?: QMutationOptions<Ops, Op>) => EndpointMutationReturn<Ops, Op>) & (<Op extends MutationOpsWithPathParams<Ops>, PathParams extends ApiPathParamsInput<Ops, Op>>(operationId: Op, pathParams: () => PathParams & (HasExcessPathParams<PathParams, ApiPathParams<Ops, Op>> extends true ? PathParams : never), options?: QMutationOptions<Ops, Op>) => EndpointMutationReturn<Ops, Op>);
339
553
  };
340
554
  //# sourceMappingURL=types.d.ts.map