@qualisero/openapi-endpoint 0.12.1 → 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/index.d.ts CHANGED
@@ -1,28 +1,21 @@
1
- import type { MaybeRefOrGetter } from 'vue';
2
- import { EndpointQueryReturn } from './openapi-query';
3
- import { EndpointMutationReturn } from './openapi-mutation';
4
- import { Operations, GetPathParameters, OpenApiConfig, QQueryOptions, QMutationOptions, IsQueryOperation } from './types';
5
- export type { OpenApiConfig, OpenApiInstance, GetResponseData, QueryClientLike, GetQueryParameters } from './types';
6
- export { queryClient } from './openapi-helpers';
7
- /** @internal */
8
- export { type EndpointQueryReturn, useEndpointQuery } from './openapi-query';
9
- /** @internal */
10
- export { type EndpointMutationReturn, useEndpointMutation } from './openapi-mutation';
1
+ import { Operations, OpenApiConfig, OpenApiInstance } from './types';
2
+ export type { OpenApiConfig, OpenApiInstance, ApiResponse, ApiResponseSafe, ApiRequest, ApiPathParams, ApiPathParamsInput, ApiQueryParams, QueryClientLike, QQueryOptions, QMutationOptions, QMutationVars, CacheInvalidationOptions, EndpointQueryReturn, EndpointMutationReturn, RequiresPathParameters, HasExcessPathParams, NoPathParams, WithPathParams, QueryOpsNoPathParams, QueryOpsWithPathParams, MutationOpsNoPathParams, MutationOpsWithPathParams, AxiosRequestConfigExtended, ReactiveOr, ReactiveValue, MutateFn, MutateAsyncFn, MutateAsyncReturn, } from './types';
3
+ export { validateMutationParams } from './types';
11
4
  /**
12
- * Creates a type-safe OpenAPI client for Vue applications.
5
+ * Create a type-safe OpenAPI client with Vue Query integration.
13
6
  *
14
7
  * This is the main entry point for the library. It provides reactive composables
15
8
  * for API operations with full TypeScript type safety based on your OpenAPI specification.
16
9
  *
10
+ * @group Setup
17
11
  * @template Ops - The operations type, typically generated from your OpenAPI spec
18
12
  * @param config - Configuration object containing operations metadata and axios instance
19
- * @returns {OpenApiInstance<Ops>} API instance with useQuery, useMutation, useEndpoint, and debug methods
13
+ * @returns {OpenApiInstance<Ops>} API instance with useQuery, useMutation, and debug methods
20
14
  *
21
15
  * @example
22
16
  * ```typescript
23
17
  * import { useOpenApi } from '@qualisero/openapi-endpoint'
24
- * // See documentation on how to generate types and operations automatically:
25
- * import { openApiOperations, type OpenApiOperations } from './generated/api-operations'
18
+ * import { openApiOperations, type OpenApiOperations, QueryOperationId, MutationOperationId } from './generated/api-operations'
26
19
  * import axios from 'axios'
27
20
  *
28
21
  * const api = useOpenApi<OpenApiOperations>({
@@ -30,183 +23,15 @@ export { type EndpointMutationReturn, useEndpointMutation } from './openapi-muta
30
23
  * axios: axios.create({ baseURL: 'https://api.example.com' })
31
24
  * })
32
25
  *
33
- * // Use in components
34
- * const { data, isLoading } = api.useQuery('listPets', {})
35
- * const createPet = api.useMutation('createPet', {})
26
+ * // Queries
27
+ * const listQuery = api.useQuery(QueryOperationId.listPets, {
28
+ * queryParams: { limit: 10 }
29
+ * })
30
+ *
31
+ * // Mutations
32
+ * const createPet = api.useMutation(MutationOperationId.createPet)
33
+ * createPet.mutate({ data: { name: 'Fluffy' } })
36
34
  * ```
37
35
  */
38
- export declare function useOpenApi<Ops extends Operations<Ops>>(config: OpenApiConfig<Ops>): {
39
- /**
40
- * Debug utility to inspect operation metadata.
41
- *
42
- * @param operationId - The operation ID to debug
43
- * @returns Information about whether the operation is a query operation
44
- */
45
- _debugIsQueryOperation: <Op extends keyof Ops>(operationId: Op) => IsQueryOperation<Ops, Op>;
46
- /**
47
- * Creates a reactive query for GET operations.
48
- *
49
- * This composable wraps TanStack Query for read-only operations with automatic
50
- * type inference, caching, and reactive updates.
51
- *
52
- * @template Op - The operation key from your operations type
53
- * @param operationId - Operation ID (must be a GET operation)
54
- * @param pathParamsOrOptions - Path parameters or query options
55
- * @param optionsOrNull - Additional query options when path params are provided
56
- * @returns Reactive query result with data, loading state, error handling, etc.
57
- *
58
- * @example
59
- * ```typescript
60
- * // Query without path parameters
61
- * const { data: pets, isLoading } = api.useQuery(OperationId.listPets, {
62
- * enabled: true,
63
- * onLoad: (data) => console.log('Loaded:', data)
64
- * })
65
- *
66
- * // Query with path parameters
67
- * const { data: pet } = api.useQuery(OperationId.getPet, { petId: '123' }, {
68
- * enabled: computed(() => Boolean(petId.value))
69
- * })
70
- * ```
71
- */
72
- 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>;
73
- /**
74
- * Creates a reactive mutation for POST/PUT/PATCH/DELETE operations.
75
- *
76
- * This composable wraps TanStack Query's useMutation for data-modifying operations
77
- * with automatic cache invalidation and optimistic updates.
78
- *
79
- * @template Op - The operation key from your operations type
80
- * @param operationId - Operation ID (must be a mutation operation)
81
- * @param pathParamsOrOptions - Path parameters or mutation options
82
- * @param optionsOrNull - Additional mutation options when path params are provided
83
- * @returns Reactive mutation result with mutate, mutateAsync, status, etc.
84
- *
85
- * @example
86
- * ```typescript
87
- * // Mutation without path parameters
88
- * const createPet = api.useMutation(OperationId.createPet, {
89
- * onSuccess: (data) => console.log('Created:', data),
90
- * onError: (error) => console.error('Failed:', error)
91
- * })
92
- *
93
- * // Mutation with path parameters
94
- * const updatePet = api.useMutation(OperationId.updatePet, { petId: '123' }, {
95
- * onSuccess: async () => {
96
- * // Automatically invalidates related queries
97
- * }
98
- * })
99
- *
100
- * // Execute the mutation
101
- * await createPet.mutateAsync({ data: { name: 'Fluffy' } })
102
- * ```
103
- */
104
- 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>) => {
105
- data: import("vue").ComputedRef<import("axios").AxiosResponse<import("./types").GetResponseData<Ops, Op>, any, {}> | undefined>;
106
- isEnabled: import("vue").ComputedRef<boolean>;
107
- extraPathParams: import("vue").Ref<GetPathParameters<Ops, Op>, GetPathParameters<Ops, Op>>;
108
- pathParams: import("vue").ComputedRef<GetPathParameters<Ops, Op>>;
109
- context: import("vue").Ref<unknown, unknown>;
110
- error: import("vue").Ref<null, null>;
111
- isError: import("vue").Ref<false, false>;
112
- isPending: import("vue").Ref<false, false>;
113
- isSuccess: import("vue").Ref<false, false>;
114
- status: import("vue").Ref<"idle", "idle">;
115
- failureCount: import("vue").Ref<number, number>;
116
- failureReason: import("vue").Ref<Error | null, Error | null>;
117
- isPaused: import("vue").Ref<boolean, boolean>;
118
- variables: import("vue").Ref<undefined, undefined>;
119
- isIdle: import("vue").Ref<true, true>;
120
- submittedAt: import("vue").Ref<number, number>;
121
- mutate: (variables: import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, options?: import("@tanstack/query-core").MutateOptions<import("axios").AxiosResponse<any, any, {}>, Error, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, unknown> | undefined) => void;
122
- mutateAsync: import("@tanstack/query-core").MutateFunction<import("axios").AxiosResponse<any, any, {}>, Error, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, unknown>;
123
- reset: import("@tanstack/query-core").MutationObserverResult<TData, TError, TVariables, TOnMutateResult>["reset"];
124
- } | {
125
- data: import("vue").ComputedRef<import("axios").AxiosResponse<import("./types").GetResponseData<Ops, Op>, any, {}> | undefined>;
126
- isEnabled: import("vue").ComputedRef<boolean>;
127
- extraPathParams: import("vue").Ref<GetPathParameters<Ops, Op>, GetPathParameters<Ops, Op>>;
128
- pathParams: import("vue").ComputedRef<GetPathParameters<Ops, Op>>;
129
- context: import("vue").Ref<unknown, unknown>;
130
- error: import("vue").Ref<null, null>;
131
- isError: import("vue").Ref<false, false>;
132
- isPending: import("vue").Ref<true, true>;
133
- isSuccess: import("vue").Ref<false, false>;
134
- status: import("vue").Ref<"pending", "pending">;
135
- failureCount: import("vue").Ref<number, number>;
136
- failureReason: import("vue").Ref<Error | null, Error | null>;
137
- isPaused: import("vue").Ref<boolean, boolean>;
138
- variables: import("@vue/shared").IfAny<import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, import("vue").Ref<import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>>, [import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>] extends [import("vue").Ref<any, any>] ? import("vue").Ref<any, any> & (import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>) : import("vue").Ref<import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>>>;
139
- isIdle: import("vue").Ref<false, false>;
140
- submittedAt: import("vue").Ref<number, number>;
141
- mutate: (variables: import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, options?: import("@tanstack/query-core").MutateOptions<import("axios").AxiosResponse<any, any, {}>, Error, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, unknown> | undefined) => void;
142
- mutateAsync: import("@tanstack/query-core").MutateFunction<import("axios").AxiosResponse<any, any, {}>, Error, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, unknown>;
143
- reset: import("@tanstack/query-core").MutationObserverResult<TData, TError, TVariables, TOnMutateResult>["reset"];
144
- } | {
145
- data: import("vue").ComputedRef<import("axios").AxiosResponse<import("./types").GetResponseData<Ops, Op>, any, {}> | undefined>;
146
- isEnabled: import("vue").ComputedRef<boolean>;
147
- extraPathParams: import("vue").Ref<GetPathParameters<Ops, Op>, GetPathParameters<Ops, Op>>;
148
- pathParams: import("vue").ComputedRef<GetPathParameters<Ops, Op>>;
149
- context: import("vue").Ref<unknown, unknown>;
150
- error: import("vue").Ref<Error, Error>;
151
- isError: import("vue").Ref<true, true>;
152
- isPending: import("vue").Ref<false, false>;
153
- isSuccess: import("vue").Ref<false, false>;
154
- status: import("vue").Ref<"error", "error">;
155
- failureCount: import("vue").Ref<number, number>;
156
- failureReason: import("vue").Ref<Error | null, Error | null>;
157
- isPaused: import("vue").Ref<boolean, boolean>;
158
- variables: import("@vue/shared").IfAny<import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, import("vue").Ref<import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>>, [import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>] extends [import("vue").Ref<any, any>] ? import("vue").Ref<any, any> & (import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>) : import("vue").Ref<import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>>>;
159
- isIdle: import("vue").Ref<false, false>;
160
- submittedAt: import("vue").Ref<number, number>;
161
- mutate: (variables: import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, options?: import("@tanstack/query-core").MutateOptions<import("axios").AxiosResponse<any, any, {}>, Error, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, unknown> | undefined) => void;
162
- mutateAsync: import("@tanstack/query-core").MutateFunction<import("axios").AxiosResponse<any, any, {}>, Error, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, unknown>;
163
- reset: import("@tanstack/query-core").MutationObserverResult<TData, TError, TVariables, TOnMutateResult>["reset"];
164
- } | {
165
- data: import("vue").ComputedRef<import("axios").AxiosResponse<import("./types").GetResponseData<Ops, Op>, any, {}> | undefined>;
166
- isEnabled: import("vue").ComputedRef<boolean>;
167
- extraPathParams: import("vue").Ref<GetPathParameters<Ops, Op>, GetPathParameters<Ops, Op>>;
168
- pathParams: import("vue").ComputedRef<GetPathParameters<Ops, Op>>;
169
- context: import("vue").Ref<unknown, unknown>;
170
- error: import("vue").Ref<null, null>;
171
- isError: import("vue").Ref<false, false>;
172
- isPending: import("vue").Ref<false, false>;
173
- isSuccess: import("vue").Ref<true, true>;
174
- status: import("vue").Ref<"success", "success">;
175
- failureCount: import("vue").Ref<number, number>;
176
- failureReason: import("vue").Ref<Error | null, Error | null>;
177
- isPaused: import("vue").Ref<boolean, boolean>;
178
- variables: import("@vue/shared").IfAny<import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, import("vue").Ref<import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>>, [import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>] extends [import("vue").Ref<any, any>] ? import("vue").Ref<any, any> & (import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>) : import("vue").Ref<import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>>>;
179
- isIdle: import("vue").Ref<false, false>;
180
- submittedAt: import("vue").Ref<number, number>;
181
- mutate: (variables: import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, options?: import("@tanstack/query-core").MutateOptions<import("axios").AxiosResponse<any, any, {}>, Error, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, unknown> | undefined) => void;
182
- mutateAsync: import("@tanstack/query-core").MutateFunction<import("axios").AxiosResponse<any, any, {}>, Error, import("./types").GetRequestBody<Ops, Op> extends never ? void | import("./types").QMutationVars<Ops, Op> : import("./types").QMutationVars<Ops, Op>, unknown>;
183
- reset: import("@tanstack/query-core").MutationObserverResult<TData, TError, TVariables, TOnMutateResult>["reset"];
184
- };
185
- /**
186
- * Generic endpoint composable that automatically detects operation type.
187
- *
188
- * This is a universal composable that returns either a query or mutation based
189
- * on the operation's HTTP method. Use this when you want unified handling.
190
- *
191
- * @template Op - The operation key from your operations type
192
- * @param operationId - Any operation ID
193
- * @param pathParamsOrOptions - Path parameters or operation options
194
- * @param optionsOrNull - Additional options when path params are provided
195
- * @returns Query result for GET operations, mutation result for others
196
- *
197
- * @example
198
- * ```typescript
199
- * // Automatically becomes a query for GET operations
200
- * const listEndpoint = api.useEndpoint(OperationId.listPets)
201
- *
202
- * // Automatically becomes a mutation for POST operations
203
- * const createEndpoint = api.useEndpoint(OperationId.createPet)
204
- *
205
- * // TypeScript knows the correct return type based on the operation
206
- * const data = listEndpoint.data // Query data
207
- * await createEndpoint.mutateAsync({ data: petData }) // Mutation execution
208
- * ```
209
- */
210
- 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>;
211
- };
36
+ export declare function useOpenApi<Ops extends Operations<Ops>>(config: OpenApiConfig<Ops>): OpenApiInstance<Ops>;
212
37
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,UAAU,EAGV,aAAa,EACb,eAAe,EAShB,MAAM,SAAS,CAAA;AAIhB,YAAY,EACV,aAAa,EACb,eAAe,EACf,WAAW,EACX,eAAe,EACf,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,wBAAwB,EACxB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,yBAAyB,EACzB,0BAA0B,EAC1B,UAAU,EACV,aAAa,EACb,QAAQ,EACR,aAAa,EACb,iBAAiB,GAClB,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,UAAU,CAAC,GAAG,SAAS,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CA2JxG"}
package/dist/index.js CHANGED
@@ -1,27 +1,23 @@
1
- import { useEndpoint } from './openapi-endpoint';
2
- import { useEndpointQuery } from './openapi-query';
3
- import { useEndpointMutation } from './openapi-mutation';
4
- import { getHelpers } from './openapi-helpers';
5
- export { queryClient } from './openapi-helpers';
6
- /** @internal */
7
- export { useEndpointQuery } from './openapi-query';
8
- /** @internal */
9
- export { useEndpointMutation } from './openapi-mutation';
1
+ import { useEndpointQuery } from './openapi-query.js';
2
+ import { useEndpointMutation } from './openapi-mutation.js';
3
+ import { getHelpers } from './openapi-helpers.js';
4
+ // Public function exports
5
+ export { validateMutationParams } from './types.js';
10
6
  /**
11
- * Creates a type-safe OpenAPI client for Vue applications.
7
+ * Create a type-safe OpenAPI client with Vue Query integration.
12
8
  *
13
9
  * This is the main entry point for the library. It provides reactive composables
14
10
  * for API operations with full TypeScript type safety based on your OpenAPI specification.
15
11
  *
12
+ * @group Setup
16
13
  * @template Ops - The operations type, typically generated from your OpenAPI spec
17
14
  * @param config - Configuration object containing operations metadata and axios instance
18
- * @returns {OpenApiInstance<Ops>} API instance with useQuery, useMutation, useEndpoint, and debug methods
15
+ * @returns {OpenApiInstance<Ops>} API instance with useQuery, useMutation, and debug methods
19
16
  *
20
17
  * @example
21
18
  * ```typescript
22
19
  * import { useOpenApi } from '@qualisero/openapi-endpoint'
23
- * // See documentation on how to generate types and operations automatically:
24
- * import { openApiOperations, type OpenApiOperations } from './generated/api-operations'
20
+ * import { openApiOperations, type OpenApiOperations, QueryOperationId, MutationOperationId } from './generated/api-operations'
25
21
  * import axios from 'axios'
26
22
  *
27
23
  * const api = useOpenApi<OpenApiOperations>({
@@ -29,118 +25,34 @@ export { useEndpointMutation } from './openapi-mutation';
29
25
  * axios: axios.create({ baseURL: 'https://api.example.com' })
30
26
  * })
31
27
  *
32
- * // Use in components
33
- * const { data, isLoading } = api.useQuery('listPets', {})
34
- * const createPet = api.useMutation('createPet', {})
28
+ * // Queries
29
+ * const listQuery = api.useQuery(QueryOperationId.listPets, {
30
+ * queryParams: { limit: 10 }
31
+ * })
32
+ *
33
+ * // Mutations
34
+ * const createPet = api.useMutation(MutationOperationId.createPet)
35
+ * createPet.mutate({ data: { name: 'Fluffy' } })
35
36
  * ```
36
37
  */
37
38
  export function useOpenApi(config) {
38
- return {
39
- /**
40
- * Debug utility to inspect operation metadata.
41
- *
42
- * @param operationId - The operation ID to debug
43
- * @returns Information about whether the operation is a query operation
44
- */
45
- _debugIsQueryOperation: function (operationId) {
46
- const helpers = getHelpers(config);
47
- const info = helpers.getOperationInfo(operationId);
48
- console.log('Operation Info:', info);
49
- return {};
50
- },
51
- /**
52
- * Creates a reactive query for GET operations.
53
- *
54
- * This composable wraps TanStack Query for read-only operations with automatic
55
- * type inference, caching, and reactive updates.
56
- *
57
- * @template Op - The operation key from your operations type
58
- * @param operationId - Operation ID (must be a GET operation)
59
- * @param pathParamsOrOptions - Path parameters or query options
60
- * @param optionsOrNull - Additional query options when path params are provided
61
- * @returns Reactive query result with data, loading state, error handling, etc.
62
- *
63
- * @example
64
- * ```typescript
65
- * // Query without path parameters
66
- * const { data: pets, isLoading } = api.useQuery(OperationId.listPets, {
67
- * enabled: true,
68
- * onLoad: (data) => console.log('Loaded:', data)
69
- * })
70
- *
71
- * // Query with path parameters
72
- * const { data: pet } = api.useQuery(OperationId.getPet, { petId: '123' }, {
73
- * enabled: computed(() => Boolean(petId.value))
74
- * })
75
- * ```
76
- */
77
- useQuery: function (operationId, pathParamsOrOptions, optionsOrNull) {
78
- const helpers = getHelpers(config);
39
+ function useQuery(operationId, pathParamsOrOptions, optionsOrNull) {
40
+ const helpers = getHelpers(config);
41
+ const { path } = helpers.getOperationInfo(operationId);
42
+ const hasPathParams = path.includes('{');
43
+ if (hasPathParams) {
79
44
  return useEndpointQuery(operationId, helpers, pathParamsOrOptions, optionsOrNull);
80
- },
81
- /**
82
- * Creates a reactive mutation for POST/PUT/PATCH/DELETE operations.
83
- *
84
- * This composable wraps TanStack Query's useMutation for data-modifying operations
85
- * with automatic cache invalidation and optimistic updates.
86
- *
87
- * @template Op - The operation key from your operations type
88
- * @param operationId - Operation ID (must be a mutation operation)
89
- * @param pathParamsOrOptions - Path parameters or mutation options
90
- * @param optionsOrNull - Additional mutation options when path params are provided
91
- * @returns Reactive mutation result with mutate, mutateAsync, status, etc.
92
- *
93
- * @example
94
- * ```typescript
95
- * // Mutation without path parameters
96
- * const createPet = api.useMutation(OperationId.createPet, {
97
- * onSuccess: (data) => console.log('Created:', data),
98
- * onError: (error) => console.error('Failed:', error)
99
- * })
100
- *
101
- * // Mutation with path parameters
102
- * const updatePet = api.useMutation(OperationId.updatePet, { petId: '123' }, {
103
- * onSuccess: async () => {
104
- * // Automatically invalidates related queries
105
- * }
106
- * })
107
- *
108
- * // Execute the mutation
109
- * await createPet.mutateAsync({ data: { name: 'Fluffy' } })
110
- * ```
111
- */
112
- useMutation: function (operationId, pathParamsOrOptions, optionsOrNull) {
113
- const helpers = getHelpers(config);
45
+ }
46
+ return useEndpointQuery(operationId, helpers, undefined, pathParamsOrOptions);
47
+ }
48
+ function useMutation(operationId, pathParamsOrOptions, optionsOrNull) {
49
+ const helpers = getHelpers(config);
50
+ const { path } = helpers.getOperationInfo(operationId);
51
+ const hasPathParams = path.includes('{');
52
+ if (hasPathParams) {
114
53
  return useEndpointMutation(operationId, helpers, pathParamsOrOptions, optionsOrNull);
115
- },
116
- /**
117
- * Generic endpoint composable that automatically detects operation type.
118
- *
119
- * This is a universal composable that returns either a query or mutation based
120
- * on the operation's HTTP method. Use this when you want unified handling.
121
- *
122
- * @template Op - The operation key from your operations type
123
- * @param operationId - Any operation ID
124
- * @param pathParamsOrOptions - Path parameters or operation options
125
- * @param optionsOrNull - Additional options when path params are provided
126
- * @returns Query result for GET operations, mutation result for others
127
- *
128
- * @example
129
- * ```typescript
130
- * // Automatically becomes a query for GET operations
131
- * const listEndpoint = api.useEndpoint(OperationId.listPets)
132
- *
133
- * // Automatically becomes a mutation for POST operations
134
- * const createEndpoint = api.useEndpoint(OperationId.createPet)
135
- *
136
- * // TypeScript knows the correct return type based on the operation
137
- * const data = listEndpoint.data // Query data
138
- * await createEndpoint.mutateAsync({ data: petData }) // Mutation execution
139
- * ```
140
- */
141
- useEndpoint: function (operationId, pathParamsOrOptions, optionsOrNull) {
142
- const helpers = getHelpers(config);
143
- return useEndpoint(operationId, helpers, pathParamsOrOptions, optionsOrNull);
144
- },
145
- };
54
+ }
55
+ return useEndpointMutation(operationId, helpers, undefined, pathParamsOrOptions);
56
+ }
57
+ return { useQuery, useMutation };
146
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openapi-helpers.d.ts","sourceRoot":"","sources":["../src/openapi-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAGpG;;;;;GAKG;AACH,QAAA,MAAM,kBAAkB,EAAE,eAIxB,CAAA;AAiBF,wBAAgB,UAAU,CAAC,GAAG,SAAS,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,EAAE,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC;oCAE/D,EAAE,KAAG,aAAa;wCAMd,EAAE,KAAG,MAAM,GAAG,IAAI;yCAiCjB,EAAE,KAAG,MAAM,GAAG,IAAI;oCAevB,EAAE,KAAG,OAAO;uCAMT,EAAE,KAAG,OAAO;;;EAcvD;AAED,MAAM,MAAM,cAAc,CAAC,GAAG,SAAS,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,IAAI,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAA;AAEtH,OAAO,EAAE,kBAAkB,IAAI,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"openapi-helpers.d.ts","sourceRoot":"","sources":["../src/openapi-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAClB,aAAa,EACb,UAAU,EACV,eAAe,EAGhB,MAAM,SAAS,CAAA;AAGhB;;;;;GAKG;AACH,QAAA,MAAM,kBAAkB,EAAE,eAIxB,CAAA;AAiEF,wBAAgB,UAAU,CAAC,GAAG,SAAS,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,EAAE,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC;oCAE/D,EAAE,KAAG,aAAa;wCAMd,EAAE,KAAG,MAAM,GAAG,IAAI;yCA6BjB,EAAE,KAAG,MAAM,GAAG,IAAI;oCAWvB,EAAE,KAAG,OAAO;uCAMT,EAAE,KAAG,OAAO;;;EAcvD;AAED,MAAM,MAAM,cAAc,CAAC,GAAG,SAAS,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,IAAI,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAA;AAEtH,OAAO,EAAE,kBAAkB,IAAI,WAAW,EAAE,CAAA"}
@@ -1,4 +1,4 @@
1
- import { HttpMethod } from './types';
1
+ import { HttpMethod, isQueryMethod, isMutationMethod, } from './types.js';
2
2
  import { QueryClient } from '@tanstack/vue-query';
3
3
  /**
4
4
  * Default QueryClient instance with pre-configured options.
@@ -11,19 +11,63 @@ const defaultQueryClient = new QueryClient({
11
11
  queries: { staleTime: 1000 * 60 * 5 },
12
12
  },
13
13
  });
14
- // Helper returning the operationId prefix given an http method
15
- function getMethodPrefix(method) {
16
- const METHOD_PREFIXES = {
17
- [HttpMethod.GET]: 'get', // or 'list' depending on the operationId
18
- [HttpMethod.POST]: 'create',
19
- [HttpMethod.PUT]: 'update',
20
- [HttpMethod.PATCH]: 'update',
21
- [HttpMethod.DELETE]: 'delete',
22
- [HttpMethod.HEAD]: null,
23
- [HttpMethod.OPTIONS]: null,
24
- [HttpMethod.TRACE]: null,
25
- };
26
- return METHOD_PREFIXES[method];
14
+ /**
15
+ * Suffixes that require adding 'es' for pluralization (e.g., 'box' -> 'boxes').
16
+ */
17
+ const PLURAL_ES_SUFFIXES = ['s', 'x', 'z', 'ch', 'sh', 'o'];
18
+ /**
19
+ * Mapping of HTTP methods to their CRUD operation name prefixes.
20
+ * Used to infer resource names from operation IDs.
21
+ */
22
+ const CRUD_PREFIXES = {
23
+ [HttpMethod.GET]: { singular: 'get', plural: 'list' },
24
+ [HttpMethod.POST]: { singular: 'create', plural: 'create' },
25
+ [HttpMethod.PUT]: { singular: 'update', plural: 'update' },
26
+ [HttpMethod.PATCH]: { singular: 'update', plural: 'update' },
27
+ [HttpMethod.DELETE]: { singular: 'delete', plural: 'delete' },
28
+ [HttpMethod.HEAD]: null,
29
+ [HttpMethod.OPTIONS]: null,
30
+ [HttpMethod.TRACE]: null,
31
+ };
32
+ /**
33
+ * Extracts the resource name from an operation ID based on its HTTP method.
34
+ * @param operationId - The operation ID (e.g., 'createPet', 'updatePet')
35
+ * @param method - The HTTP method
36
+ * @returns The resource name (e.g., 'Pet') or null if not extractable
37
+ */
38
+ function getResourceName(operationId, method) {
39
+ const prefixes = CRUD_PREFIXES[method];
40
+ if (!prefixes)
41
+ return null;
42
+ // Try singular prefix first (get, create, update, delete)
43
+ if (operationId.startsWith(prefixes.singular)) {
44
+ const remaining = operationId.slice(prefixes.singular.length);
45
+ if (remaining.length > 0 && /^[A-Z]/.test(remaining)) {
46
+ return remaining;
47
+ }
48
+ }
49
+ // Try plural prefix (list)
50
+ if (operationId.startsWith(prefixes.plural)) {
51
+ const remaining = operationId.slice(prefixes.plural.length);
52
+ if (remaining.length > 0 && /^[A-Z]/.test(remaining)) {
53
+ return remaining;
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+ /**
59
+ * Pluralizes a resource name using common English rules.
60
+ * @param name - The singular resource name
61
+ * @returns The pluralized name
62
+ */
63
+ function pluralizeResource(name) {
64
+ if (name.endsWith('y')) {
65
+ return name.slice(0, -1) + 'ies';
66
+ }
67
+ else if (PLURAL_ES_SUFFIXES.some((suffix) => name.endsWith(suffix))) {
68
+ return name + 'es';
69
+ }
70
+ return name + 's';
27
71
  }
28
72
  export function getHelpers(config) {
29
73
  // Helper function to get operation info by ID
@@ -31,32 +75,23 @@ export function getHelpers(config) {
31
75
  return config.operations[operationId];
32
76
  }
33
77
  // Helper to return a url path for matching list endpoint (e.g. /items/123 -> /items/)
34
- // Based on operationId prefix: createItem, updateItem -> listItems
78
+ // Based on operationId prefix: createItem, updateItem -> listItem
35
79
  function getListOperationPath(operationId) {
36
80
  const opInfo = getOperationInfo(operationId);
37
81
  const operationIdStr = operationId;
38
- const operationPrefix = opInfo ? getMethodPrefix(opInfo.method) : null;
39
- // Make sure operationId matches `<operationPrefix><upercase resourceName>` pattern
40
- if (!operationPrefix || !/^[A-Z]/.test(operationIdStr.charAt(operationPrefix.length)))
41
- // If not, fallback to CRUD heuristic
82
+ // Try to extract resource name from operation ID
83
+ const resourceName = getResourceName(operationIdStr, opInfo.method);
84
+ if (!resourceName) {
85
+ // Fallback to CRUD heuristic based on path structure
42
86
  return getCrudListPathPrefix(operationId);
43
- const resourceName = operationIdStr.substring(operationPrefix.length);
87
+ }
88
+ // Try to find list operation with same resource name
44
89
  const listOperationId = `list${resourceName}`;
45
90
  let listOperationInfo = getOperationInfo(listOperationId);
91
+ // If not found, try pluralized version
46
92
  if (!listOperationInfo) {
47
- // Try pluralizing the resource name (simple heuristic)
48
- let pluralResourceName = resourceName;
49
- const addEsSuffixes = ['s', 'x', 'z', 'ch', 'sh', 'o'];
50
- if (resourceName.endsWith('y')) {
51
- pluralResourceName = resourceName.slice(0, -1) + 'ies';
52
- }
53
- else if (addEsSuffixes.some((suffix) => resourceName.endsWith(suffix))) {
54
- pluralResourceName = resourceName + 'es';
55
- }
56
- else {
57
- pluralResourceName = resourceName + 's';
58
- }
59
- listOperationInfo = getOperationInfo(`list${pluralResourceName}`);
93
+ const pluralName = pluralizeResource(resourceName);
94
+ listOperationInfo = getOperationInfo(`list${pluralName}`);
60
95
  }
61
96
  if (listOperationInfo && listOperationInfo.method === HttpMethod.GET) {
62
97
  return listOperationInfo.path;
@@ -74,18 +109,15 @@ export function getHelpers(config) {
74
109
  }
75
110
  return null;
76
111
  }
77
- // Constants for HTTP method categorization
78
- const QUERY_METHODS = [HttpMethod.GET, HttpMethod.HEAD, HttpMethod.OPTIONS];
79
- const MUTATION_METHODS = [HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH, HttpMethod.DELETE];
80
112
  // Helper to check if an operation is a query method at runtime
81
113
  function isQueryOperation(operationId) {
82
114
  const { method } = getOperationInfo(operationId);
83
- return QUERY_METHODS.includes(method);
115
+ return isQueryMethod(method);
84
116
  }
85
117
  // Helper to check if an operation is a mutation method at runtime
86
118
  function isMutationOperation(operationId) {
87
119
  const { method } = getOperationInfo(operationId);
88
- return MUTATION_METHODS.includes(method);
120
+ return isMutationMethod(method);
89
121
  }
90
122
  return {
91
123
  getOperationInfo,