@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/dist/types.d.ts CHANGED
@@ -1,94 +1,11 @@
1
1
  import { type AxiosInstance, type AxiosError, type AxiosRequestConfig, type AxiosResponse } from 'axios';
2
2
  import type { MutationObserverOptions, QueryKey, QueryObserverOptions } from '@tanstack/query-core';
3
3
  import type { ComputedRef, Ref } from 'vue';
4
- import type { EndpointQueryReturn } from './openapi-query';
5
- import type { EndpointMutationReturn } from './openapi-mutation';
4
+ import type { QueryClient } from '@tanstack/vue-query';
6
5
  /**
7
6
  * Extended Axios request configuration that allows custom properties.
8
7
  */
9
8
  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);
40
- /** @internal */
41
- export type { EndpointQueryReturn, EndpointMutationReturn };
42
- /**
43
- * Interface defining the minimal QueryClient methods required by this library.
44
- *
45
- * This interface ensures compatibility with different versions of @tanstack/vue-query
46
- * by only requiring the specific methods that are actually used internally.
47
- *
48
- * @group Types
49
- */
50
- export interface QueryClientLike {
51
- cancelQueries(filters: {
52
- queryKey: unknown[];
53
- exact?: boolean;
54
- }): Promise<void>;
55
- setQueryData(queryKey: unknown[], data: unknown): void;
56
- invalidateQueries(filters: {
57
- queryKey?: unknown[];
58
- exact?: boolean;
59
- predicate?: (query: {
60
- queryKey: readonly unknown[];
61
- }) => boolean;
62
- }): Promise<void>;
63
- }
64
- /** @internal */
65
- export type Operations<Ops> = object & {
66
- [K in keyof Ops]: OperationInfo;
67
- };
68
- /**
69
- * Configuration object for initializing the OpenAPI client.
70
- *
71
- * @template Ops - The operations type, typically generated from your OpenAPI specification
72
- *
73
- * @example
74
- * ```typescript
75
- * import { useOpenApi } from '@qualisero/openapi-endpoint'
76
- * import { openApiOperations, type OpenApiOperations } from './generated/api-operations'
77
- * import axios from 'axios'
78
- *
79
- * const config: OpenApiConfig<OpenApiOperations> = {
80
- * operations: openApiOperations,
81
- * axios: axios.create({ baseURL: 'https://api.example.com' }),
82
- * queryClient: customQueryClient // optional
83
- * }
84
- * ```
85
- */
86
- export interface OpenApiConfig<Ops extends Operations<Ops>> {
87
- operations: Ops;
88
- axios: AxiosInstance;
89
- queryClient?: QueryClientLike;
90
- }
91
- /** @internal */
92
9
  export declare enum HttpMethod {
93
10
  GET = "GET",
94
11
  POST = "POST",
@@ -99,159 +16,250 @@ export declare enum HttpMethod {
99
16
  OPTIONS = "OPTIONS",
100
17
  TRACE = "TRACE"
101
18
  }
102
- /**
103
- * HTTP methods that are considered read-only query operations.
104
- * These can be used with useQuery() and support caching.
105
- */
106
19
  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
20
  export declare const MUTATION_METHODS: readonly [HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH, HttpMethod.DELETE];
111
- /** @internal */
112
21
  export declare function isQueryMethod(method: HttpMethod): boolean;
113
- /** @internal */
114
22
  export declare function isMutationMethod(method: HttpMethod): boolean;
115
- /** @internal */
116
- export interface OperationInfo {
117
- path: string;
118
- method: HttpMethod;
119
- }
120
- /** @internal */
121
- export type GetOperation<Ops extends Operations<Ops>, Op extends keyof Ops> = Ops[Op];
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
23
  /**
135
- * Extract the raw response data type from an operation without modifications.
136
- * @internal
24
+ * A value that can be reactive (ref, computed, getter function) or direct.
137
25
  */
138
- type ExtractResponseData<Ops extends Operations<Ops>, Op extends keyof Ops> = GetOperation<Ops, Op> extends {
139
- responses: {
140
- 200: {
141
- content: {
142
- 'application/json': infer Data;
143
- };
144
- };
145
- };
146
- } ? Data : unknown;
26
+ export type ReactiveOr<T> = T | Ref<T> | ComputedRef<T> | (() => T);
147
27
  /**
148
- * Extract response data type from an operation (all fields required).
28
+ * Constrains a getter function `F` so that its return type has no excess
29
+ * properties beyond the expected type `T`.
149
30
  *
150
- * All fields are REQUIRED regardless of their `required` status in the OpenAPI schema.
151
- * This assumes the server always returns complete objects.
31
+ * Evaluates to `F` when the return type is valid, or `never` when the
32
+ * function returns unexpected extra properties causing a type error at the
33
+ * call site.
152
34
  *
153
35
  * @example
154
- * ```typescript
155
- * type PetResponse = ApiResponse<OpenApiOperations, 'getPet'>
156
- * // { readonly id: string, name: string, ... } - all required
36
+ * ```ts
37
+ * type PP = { petId: string | undefined }
38
+ * type F1 = () => { petId: string } // NoExcessReturn<PP, F1> → F1 ✅
39
+ * type F2 = () => { petId: string; bad: 'x' } // NoExcessReturn<PP, F2> → never ❌
157
40
  * ```
41
+ *
42
+ * @internal Used in generated `api-client.ts` to enforce strict path params on getter fns.
158
43
  */
159
- export type ApiResponse<Ops extends Operations<Ops>, Op extends keyof Ops> = RequireAll<ExtractResponseData<Ops, Op>>;
44
+ export type NoExcessReturn<T extends Record<string, unknown>, F extends () => T> = Exclude<keyof ReturnType<F>, keyof T> extends never ? F : never;
160
45
  /**
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
- * ```
46
+ * Reactive value that excludes function getters.
47
+ * @internal Used for internal type inference.
170
48
  */
171
- export type ApiResponseSafe<Ops extends Operations<Ops>, Op extends keyof Ops> = RequireReadonly<ExtractResponseData<Ops, Op>>;
49
+ export type ReactiveValue<T> = T | Ref<T> | ComputedRef<T>;
172
50
  /**
173
- * A value that can be reactive (ref, computed) or direct.
174
- * Standardized pattern for all reactive values across the library.
51
+ * Runtime configuration for a single endpoint. Passed directly to
52
+ * `useEndpointQuery` / `useEndpointMutation` by generated code.
175
53
  *
176
- * @internal
54
+ * Created by the generated `createApiClient` factory and embedded per-operation
55
+ * in the generated `api-client.ts`.
177
56
  */
178
- export type ReactiveOr<T> = T | Ref<T> | ComputedRef<T> | (() => T);
57
+ export interface EndpointConfig {
58
+ axios: AxiosInstance;
59
+ queryClient: QueryClient;
60
+ /** The OpenAPI path template, e.g. `/pets/{petId}` */
61
+ path: string;
62
+ method: HttpMethod;
63
+ /**
64
+ * Pre-computed list path for cache invalidation after mutations.
65
+ * e.g. for `updatePet` at `/pets/{petId}`, this would be `/pets`.
66
+ * `null` means no list invalidation.
67
+ * Generated at code-gen time by the CLI.
68
+ */
69
+ listPath?: string | null;
70
+ /**
71
+ * Registry of all operations' paths, used to resolve `invalidateOperations`
72
+ * option at mutation time. Generated and embedded by the CLI.
73
+ */
74
+ operationsRegistry?: Readonly<Record<string, {
75
+ path: string;
76
+ }>>;
77
+ }
179
78
  /**
180
- * Reactive value that excludes function getters.
181
- * Useful for path params where function overloads have stricter checks.
182
- *
183
- * @internal
79
+ * Minimal interface satisfied by `QueryReturn`. Used for `refetchEndpoints`
80
+ * in cache invalidation options.
184
81
  */
185
- export type ReactiveValue<T> = T | Ref<T> | ComputedRef<T>;
186
- /** @internal */
82
+ export interface Refetchable {
83
+ refetch: () => Promise<void>;
84
+ }
85
+ /**
86
+ * Options for controlling automatic cache invalidation after mutations.
87
+ */
88
+ export interface CacheInvalidationOptions {
89
+ /** Skip automatic cache invalidation. @default false */
90
+ dontInvalidate?: boolean;
91
+ /** Skip automatic cache update for PUT/PATCH responses. @default false */
92
+ dontUpdateCache?: boolean;
93
+ /**
94
+ * Additional operation IDs to invalidate after mutation succeeds.
95
+ * Array of operation name strings, or map of operation name → path params.
96
+ * @example ['listPets']
97
+ * @example { getPet: { petId: '123' } }
98
+ */
99
+ invalidateOperations?: string[] | Record<string, Record<string, string | undefined>>;
100
+ /** Specific query endpoints to refetch after mutation succeeds. */
101
+ refetchEndpoints?: Refetchable[];
102
+ }
187
103
  type MaybeRefLeaf<T> = T | Ref<T> | ComputedRef<T>;
188
104
  type MaybeRefDeep<T> = T extends (...args: never[]) => unknown ? T : T extends object ? {
189
105
  [K in keyof T]: MaybeRefDeep<T[K]>;
190
106
  } : MaybeRefLeaf<T>;
191
- /** @internal */
192
- type ShallowOption = {
107
+ type BaseQueryOptions<TResponse, _TQueryParams extends Record<string, unknown>> = MaybeRefDeep<QueryObserverOptions<TResponse, Error, TResponse, TResponse, QueryKey>> & {
193
108
  shallow?: boolean;
194
109
  };
195
110
  /**
196
- * Extract path parameters type from an operation (truly required).
111
+ * Options for `useQuery` composable. Accepts all TanStack Query options plus:
112
+ * - `enabled`: reactive boolean
113
+ * - `queryParams`: reactive query string parameters
114
+ * - `onLoad`: callback when data loads for the first time
115
+ * - `errorHandler`: custom error handler
116
+ * - `axiosOptions`: additional axios config
117
+ *
118
+ * @template TResponse The response data type for this operation
119
+ * @template TQueryParams The query parameters type for this operation
120
+ */
121
+ export type QueryOptions<TResponse, TQueryParams extends Record<string, unknown> = Record<string, never>> = Omit<BaseQueryOptions<TResponse, TQueryParams>, 'queryKey' | 'queryFn' | 'enabled'> & {
122
+ enabled?: ReactiveOr<boolean>;
123
+ onLoad?: (data: TResponse) => void;
124
+ axiosOptions?: AxiosRequestConfigExtended;
125
+ errorHandler?: (error: AxiosError) => TResponse | void | Promise<TResponse | void>;
126
+ queryParams?: ReactiveOr<TQueryParams>;
127
+ };
128
+ type MutationVarsBase<TPathParams extends Record<string, unknown>, TQueryParams extends Record<string, unknown>> = CacheInvalidationOptions & {
129
+ pathParams?: Partial<TPathParams>;
130
+ axiosOptions?: AxiosRequestConfigExtended;
131
+ queryParams?: TQueryParams;
132
+ };
133
+ /**
134
+ * Variables passed to `mutation.mutate()` or `mutation.mutateAsync()`.
197
135
  *
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.
136
+ * When `TRequest` is `never` (operation has no request body), `data` is excluded.
200
137
  *
201
- * @example
202
- * ```typescript
203
- * type Params = ApiPathParams<OpenApiOperations, 'getPet'>
204
- * // { petId: string } - all params required
205
- * ```
138
+ * @template TPathParams Path parameters type
139
+ * @template TRequest Request body type (`never` if none)
140
+ * @template TQueryParams Query parameters type
206
141
  */
207
- export type ApiPathParams<Ops extends Operations<Ops>, Op extends keyof Ops> = Ops[Op] extends {
208
- parameters: {
209
- path: infer PathParams;
210
- };
211
- } ? PathParams extends Record<string, unknown> ? PathParams : Record<string, never> : Record<string, never>;
142
+ export type MutationVars<TPathParams extends Record<string, unknown>, TRequest, TQueryParams extends Record<string, unknown> = Record<string, never>> = [TRequest] extends [never] ? MutationVarsBase<TPathParams, TQueryParams> : MutationVarsBase<TPathParams, TQueryParams> & {
143
+ data?: TRequest;
144
+ };
145
+ type BaseMutationOptions<TResponse, TPathParams extends Record<string, unknown>, TRequest, TQueryParams extends Record<string, unknown>> = MaybeRefDeep<MutationObserverOptions<AxiosResponse<TResponse>, Error, MutationVars<TPathParams, TRequest, TQueryParams>, unknown>> & {
146
+ shallow?: boolean;
147
+ };
212
148
  /**
213
- * Path params input type that allows undefined values for reactive resolution.
149
+ * Options for `useMutation` composable.
214
150
  *
215
- * @internal
151
+ * @template TResponse Response data type
152
+ * @template TPathParams Path parameters type
153
+ * @template TRequest Request body type
154
+ * @template TQueryParams Query parameters type
216
155
  */
217
- export type ApiPathParamsInput<Ops extends Operations<Ops>, Op extends keyof Ops> = {
218
- [K in keyof ApiPathParams<Ops, Op>]: ApiPathParams<Ops, Op>[K] | undefined;
156
+ export type MutationOptions<TResponse, TPathParams extends Record<string, unknown>, TRequest, TQueryParams extends Record<string, unknown> = Record<string, never>> = Omit<BaseMutationOptions<TResponse, TPathParams, TRequest, TQueryParams>, 'mutationFn' | 'mutationKey'> & CacheInvalidationOptions & {
157
+ axiosOptions?: AxiosRequestConfigExtended;
158
+ queryParams?: ReactiveOr<TQueryParams>;
219
159
  };
220
160
  /**
221
- * Extract query parameters type from an operation.
222
- * @example
223
- * ```typescript
224
- * type Params = ApiQueryParams<OpenApiOperations, 'listPets'>
225
- * // { limit?: number, status?: string }
226
- * ```
161
+ * Return type of `mutation.mutateAsync()`.
227
162
  */
228
- export type ApiQueryParams<Ops extends Operations<Ops>, Op extends keyof Ops> = Ops[Op] extends {
229
- parameters: {
230
- query?: infer QueryParams;
163
+ export type MutateAsyncReturn<TResponse> = Promise<AxiosResponse<TResponse>>;
164
+ /**
165
+ * `mutation.mutate()` function signature.
166
+ */
167
+ export type MutateFn<TPathParams extends Record<string, unknown>, TRequest, TQueryParams extends Record<string, unknown> = Record<string, never>> = (vars?: MutationVars<TPathParams, TRequest, TQueryParams>) => void;
168
+ /**
169
+ * `mutation.mutateAsync()` function signature.
170
+ */
171
+ export type MutateAsyncFn<TResponse, TPathParams extends Record<string, unknown>, TRequest, TQueryParams extends Record<string, unknown> = Record<string, never>> = (vars?: MutationVars<TPathParams, TRequest, TQueryParams>) => MutateAsyncReturn<TResponse>;
172
+ /**
173
+ * Constraint for operation objects. Accepts any object type including
174
+ * interfaces with known keys (like those generated by openapi-typescript).
175
+ */
176
+ type AnyOps = object;
177
+ type RequireAll<T> = {
178
+ [K in keyof T]-?: T[K];
179
+ };
180
+ type IfEquals<X, Y, A = X, B = never> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B;
181
+ type IsReadonly<T, K extends keyof T> = IfEquals<Pick<T, K>, {
182
+ -readonly [Q in K]: T[K];
183
+ }, false, true>;
184
+ type RequireReadonly<T> = {
185
+ [K in keyof T as IsReadonly<T, K> extends true ? K : never]-?: T[K];
186
+ } & {
187
+ [K in keyof T as IsReadonly<T, K> extends false ? K : never]: T[K];
188
+ };
189
+ type ExtractResponseData<Ops extends AnyOps, Op extends keyof Ops> = Ops[Op] extends {
190
+ responses: {
191
+ 200: {
192
+ content: {
193
+ 'application/json': infer Data;
194
+ };
195
+ };
231
196
  };
232
- } ? QueryParams extends Record<string, unknown> ? {
233
- [K in keyof QueryParams]?: QueryParams[K];
234
- } : Record<string, never> : Record<string, never>;
197
+ } ? Data : Ops[Op] extends {
198
+ responses: {
199
+ 201: {
200
+ content: {
201
+ 'application/json': infer Data;
202
+ };
203
+ };
204
+ };
205
+ } ? Data : Ops[Op] extends {
206
+ responses: {
207
+ 202: {
208
+ content: {
209
+ 'application/json': infer Data;
210
+ };
211
+ };
212
+ };
213
+ } ? Data : Ops[Op] extends {
214
+ responses: {
215
+ 203: {
216
+ content: {
217
+ 'application/json': infer Data;
218
+ };
219
+ };
220
+ };
221
+ } ? Data : Ops[Op] extends {
222
+ responses: {
223
+ 204: {
224
+ content: {
225
+ 'application/json': infer Data;
226
+ };
227
+ };
228
+ };
229
+ } ? Data : Ops[Op] extends {
230
+ responses: {
231
+ 206: {
232
+ content: {
233
+ 'application/json': infer Data;
234
+ };
235
+ };
236
+ };
237
+ } ? Data : unknown;
238
+ /**
239
+ * Extract the response data type (all fields required).
240
+ * @example `ApiResponse<operations, 'getPet'>` → `{ readonly id: string, name: string, ... }`
241
+ */
242
+ export type ApiResponse<Ops extends AnyOps, Op extends keyof Ops> = RequireAll<ExtractResponseData<Ops, Op>>;
243
+ /**
244
+ * Extract the response data type (only readonly fields required).
245
+ */
246
+ export type ApiResponseSafe<Ops extends AnyOps, Op extends keyof Ops> = RequireReadonly<ExtractResponseData<Ops, Op>>;
235
247
  type Writable<T> = {
236
248
  -readonly [K in keyof T as IfEquals<Pick<T, K>, {
237
249
  -readonly [Q in K]: T[K];
238
250
  }, false, true> extends false ? K : never]: T[K];
239
251
  };
240
252
  /**
241
- * Extract request body type from an operation.
242
- * @example
243
- * ```typescript
244
- * type Body = ApiRequest<OpenApiOperations, 'createPet'>
245
- * // { name: string, species?: string }
246
- * ```
253
+ * Extract the request body type.
254
+ * @example `ApiRequest<operations, 'createPet'>` → `{ name: string, species?: string }`
247
255
  */
248
- export type ApiRequest<Ops extends Operations<Ops>, Op extends keyof Ops> = GetOperation<Ops, Op> extends {
256
+ export type ApiRequest<Ops extends AnyOps, Op extends keyof Ops> = Ops[Op] extends {
249
257
  requestBody: {
250
258
  content: {
251
259
  'application/json': infer Body;
252
260
  };
253
261
  };
254
- } ? Writable<Body> : GetOperation<Ops, Op> extends {
262
+ } ? Writable<Body> : Ops[Op] extends {
255
263
  requestBody: {
256
264
  content: {
257
265
  'multipart/form-data': infer Body;
@@ -259,296 +267,31 @@ export type ApiRequest<Ops extends Operations<Ops>, Op extends keyof Ops> = GetO
259
267
  };
260
268
  } ? Writable<Body> | FormData : never;
261
269
  /**
262
- * Options for controlling automatic cache invalidation and updates after mutations.
263
- *
264
- * By default, mutations automatically:
265
- * - Update cache for PUT/PATCH responses with the returned data
266
- * - Invalidate matching GET queries to trigger refetches
267
- *
268
- * @group Types
269
- */
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;
277
- /**
278
- * Skip automatic cache update for PUT/PATCH responses.
279
- *
280
- * @default false
281
- */
282
- dontUpdateCache?: boolean;
283
- /**
284
- * Additional operations to invalidate after mutation succeeds.
285
- *
286
- * Can be either:
287
- * - Array of operation IDs: `['listPets', 'getPetStats']`
288
- * - Map of operation ID to path params: `{ getPet: { petId: '123' } }`
289
- *
290
- * @example
291
- * ```typescript
292
- * // Invalidate list when creating
293
- * { invalidateOperations: ['listPets'] }
294
- *
295
- * // Invalidate specific item
296
- * { invalidateOperations: { getPet: { petId: '123' } } }
297
- * ```
298
- */
299
- invalidateOperations?: (keyof Ops)[] | Partial<{
300
- [K in keyof Ops]: ApiPathParams<Ops, K>;
301
- }>;
302
- /**
303
- * Specific query endpoints to refetch after mutation succeeds.
304
- *
305
- * Use when you have specific query results that need to be refetched.
306
- *
307
- * @example
308
- * ```typescript
309
- * const listQuery = api.useQuery('listPets')
310
- * { refetchEndpoints: [listQuery] }
311
- * ```
312
- */
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
270
+ * Extract path parameters type (all required).
271
+ * @example `ApiPathParams<operations, 'getPet'>` → `{ petId: string }`
339
272
  */
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;
273
+ export type ApiPathParams<Ops extends AnyOps, Op extends keyof Ops> = Ops[Op] extends {
274
+ parameters: {
275
+ path: infer PathParams;
276
+ };
277
+ } ? PathParams extends Record<string, unknown> ? PathParams : Record<string, never> : Record<string, never>;
408
278
  /**
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
279
+ * Path params input type same as `ApiPathParams` but all values allow `undefined`
280
+ * (for reactive resolution where params may not yet be set).
416
281
  */
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>>;
282
+ export type ApiPathParamsInput<Ops extends AnyOps, Op extends keyof Ops> = {
283
+ [K in keyof ApiPathParams<Ops, Op>]: ApiPathParams<Ops, Op>[K] | undefined;
453
284
  };
454
285
  /**
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
- * ```
286
+ * Extract query parameters type (all optional).
287
+ * @example `ApiQueryParams<operations, 'listPets'>` → `{ limit?: number, status?: string }`
468
288
  */
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>> = {
505
- /**
506
- * Execute a type-safe query (GET/HEAD/OPTIONS) with automatic caching.
507
- *
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
513
- *
514
- * @example
515
- * ```typescript
516
- * // No path params
517
- * const listQuery = api.useQuery('listPets', { queryParams: { limit: 10 } })
518
- *
519
- * // With path params (direct object)
520
- * const petQuery = api.useQuery('getPet', { petId: '123' })
521
- *
522
- * // With path params (reactive function)
523
- * const id = ref('')
524
- * const detailsQuery = api.useQuery('getPet', () => ({ petId: id.value }))
525
- * ```
526
- */
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>);
528
- /**
529
- * Execute a type-safe mutation (POST/PUT/PATCH/DELETE) with automatic cache updates.
530
- *
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
536
- *
537
- * @example
538
- * ```typescript
539
- * // No path params
540
- * const createPet = api.useMutation('createPet')
541
- * createPet.mutate({ data: { name: 'Fluffy' } })
542
- *
543
- * // With path params (direct object)
544
- * const updatePet = api.useMutation('updatePet', { petId: '123' })
545
- * updatePet.mutate({ data: { name: 'Updated' } })
546
- *
547
- * // With path params (reactive function)
548
- * const id = ref('')
549
- * const deletePet = api.useMutation('deletePet', () => ({ petId: id.value }))
550
- * ```
551
- */
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>);
553
- };
289
+ export type ApiQueryParams<Ops extends AnyOps, Op extends keyof Ops> = Ops[Op] extends {
290
+ parameters: {
291
+ query?: infer QueryParams;
292
+ };
293
+ } ? QueryParams extends Record<string, unknown> ? {
294
+ [K in keyof QueryParams]?: QueryParams[K];
295
+ } : Record<string, never> : Record<string, never>;
296
+ export {};
554
297
  //# sourceMappingURL=types.d.ts.map