vue-api-kit 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +235 -7
- package/dist/core/client.d.ts +44 -2
- package/dist/core/types.d.ts +113 -16
- package/dist/index.d.ts +2 -0
- package/dist/index.js +404 -390
- package/dist/index.js.map +1 -1
- package/package.json +22 -3
package/README.md
CHANGED
|
@@ -1,15 +1,243 @@
|
|
|
1
|
-
# vue-api-kit
|
|
1
|
+
# 🚀 vue-api-kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A powerful and type-safe API client for Vue 3 applications with built-in validation using Zod.
|
|
4
|
+
|
|
5
|
+
## 📦 Installation
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
|
-
|
|
8
|
+
npm install vue-api-kit
|
|
7
9
|
```
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
## ⚡ Quick Start
|
|
10
12
|
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
+
```typescript
|
|
14
|
+
import { createApiClient } from 'vue-api-kit';
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
|
|
17
|
+
// Define your API client
|
|
18
|
+
const api = createApiClient({
|
|
19
|
+
baseURL: 'https://jsonplaceholder.typicode.com',
|
|
20
|
+
queries: {
|
|
21
|
+
getUsers: {
|
|
22
|
+
path: '/users',
|
|
23
|
+
response: z.array(z.object({
|
|
24
|
+
id: z.number(),
|
|
25
|
+
name: z.string(),
|
|
26
|
+
email: z.string()
|
|
27
|
+
}))
|
|
28
|
+
},
|
|
29
|
+
getUser: {
|
|
30
|
+
path: '/users/{id}',
|
|
31
|
+
params: z.object({ id: z.number() }),
|
|
32
|
+
response: z.object({
|
|
33
|
+
id: z.number(),
|
|
34
|
+
name: z.string(),
|
|
35
|
+
email: z.string()
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
mutations: {
|
|
40
|
+
createUser: {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
path: '/users',
|
|
43
|
+
data: z.object({
|
|
44
|
+
name: z.string(),
|
|
45
|
+
email: z.string().email()
|
|
46
|
+
}),
|
|
47
|
+
response: z.object({
|
|
48
|
+
id: z.number(),
|
|
49
|
+
name: z.string(),
|
|
50
|
+
email: z.string()
|
|
51
|
+
})
|
|
52
|
+
},
|
|
53
|
+
updateUser: {
|
|
54
|
+
method: 'PUT',
|
|
55
|
+
path: '/users/{id}',
|
|
56
|
+
params: z.object({ id: z.number() }),
|
|
57
|
+
data: z.object({
|
|
58
|
+
name: z.string(),
|
|
59
|
+
email: z.string().email()
|
|
60
|
+
})
|
|
61
|
+
},
|
|
62
|
+
deleteUser: {
|
|
63
|
+
method: 'DELETE',
|
|
64
|
+
path: '/users/{id}',
|
|
65
|
+
params: z.object({ id: z.number() })
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
13
69
|
```
|
|
14
70
|
|
|
15
|
-
|
|
71
|
+
## 📖 Usage in Vue Components
|
|
72
|
+
|
|
73
|
+
### Queries (GET requests)
|
|
74
|
+
|
|
75
|
+
```vue
|
|
76
|
+
<script setup lang="ts">
|
|
77
|
+
import { api } from './api';
|
|
78
|
+
|
|
79
|
+
// Simple query - loads automatically on mount
|
|
80
|
+
const { result, isLoading, errorMessage } = api.query.getUsers();
|
|
81
|
+
|
|
82
|
+
// Query with parameters
|
|
83
|
+
const userId = ref(1);
|
|
84
|
+
const { result: user, isLoading: loading, refetch } = api.query.getUser({
|
|
85
|
+
params: { id: userId }
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Query with options
|
|
89
|
+
const { result: data } = api.query.getUsers({
|
|
90
|
+
loadOnMount: true,
|
|
91
|
+
debounce: 300,
|
|
92
|
+
onResult: (data) => {
|
|
93
|
+
console.log('Data loaded:', data);
|
|
94
|
+
},
|
|
95
|
+
onError: (error) => {
|
|
96
|
+
console.error('Error:', error);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
</script>
|
|
100
|
+
|
|
101
|
+
<template>
|
|
102
|
+
<div>
|
|
103
|
+
<div v-if="isLoading">Loading...</div>
|
|
104
|
+
<div v-else-if="errorMessage">Error: {{ errorMessage }}</div>
|
|
105
|
+
<ul v-else>
|
|
106
|
+
<li v-for="user in result" :key="user.id">
|
|
107
|
+
{{ user.name }}
|
|
108
|
+
</li>
|
|
109
|
+
</ul>
|
|
110
|
+
</div>
|
|
111
|
+
</template>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Mutations (POST, PUT, DELETE)
|
|
115
|
+
|
|
116
|
+
```vue
|
|
117
|
+
<script setup lang="ts">
|
|
118
|
+
import { api } from './api';
|
|
119
|
+
import { ref } from 'vue';
|
|
120
|
+
|
|
121
|
+
const { mutate, isLoading, result, errorMessage } = api.mutation.createUser({
|
|
122
|
+
onResult: (data) => {
|
|
123
|
+
console.log('User created:', data);
|
|
124
|
+
},
|
|
125
|
+
onError: (error) => {
|
|
126
|
+
console.error('Error:', error);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const name = ref('');
|
|
131
|
+
const email = ref('');
|
|
132
|
+
|
|
133
|
+
async function handleSubmit() {
|
|
134
|
+
await mutate({
|
|
135
|
+
name: name.value,
|
|
136
|
+
email: email.value
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
</script>
|
|
140
|
+
|
|
141
|
+
<template>
|
|
142
|
+
<form @submit.prevent="handleSubmit">
|
|
143
|
+
<input v-model="name" placeholder="Name" />
|
|
144
|
+
<input v-model="email" placeholder="Email" />
|
|
145
|
+
<button type="submit" :disabled="isLoading">
|
|
146
|
+
{{ isLoading ? 'Creating...' : 'Create User' }}
|
|
147
|
+
</button>
|
|
148
|
+
<p v-if="errorMessage" class="error">{{ errorMessage }}</p>
|
|
149
|
+
</form>
|
|
150
|
+
</template>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## 🎯 Features
|
|
154
|
+
|
|
155
|
+
- ✅ **Type-Safe**: Full TypeScript support with automatic type inference
|
|
156
|
+
- ✅ **Zod Validation**: Built-in request/response validation
|
|
157
|
+
- ✅ **Vue 3 Composition API**: Reactive state management
|
|
158
|
+
- ✅ **Auto Loading States**: Built-in loading, error, and success states
|
|
159
|
+
- ✅ **File Upload**: Support for multipart/form-data
|
|
160
|
+
- ✅ **Path Parameters**: Automatic path parameter replacement
|
|
161
|
+
- ✅ **Debouncing**: Built-in request debouncing
|
|
162
|
+
- ✅ **Global Error Handling**: Centralized error management
|
|
163
|
+
- ✅ **Request Interceptors**: Modify requests before sending
|
|
164
|
+
|
|
165
|
+
## 🔧 Advanced Configuration
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
const api = createApiClient({
|
|
169
|
+
baseURL: 'https://api.example.com',
|
|
170
|
+
headers: {
|
|
171
|
+
'Authorization': 'Bearer token'
|
|
172
|
+
},
|
|
173
|
+
withCredentials: true,
|
|
174
|
+
|
|
175
|
+
// Global handlers
|
|
176
|
+
onBeforeRequest: async (config) => {
|
|
177
|
+
// Modify request before sending
|
|
178
|
+
const token = localStorage.getItem('token');
|
|
179
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
180
|
+
return config;
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
onStartRequest: async () => {
|
|
184
|
+
// Called when request starts
|
|
185
|
+
console.log('Request started');
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
onFinishRequest: async () => {
|
|
189
|
+
// Called when request finishes
|
|
190
|
+
console.log('Request finished');
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
onErrorRequest: (error) => {
|
|
194
|
+
// Global error handler
|
|
195
|
+
console.error('API Error:', error.message);
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
onZodError: (issues) => {
|
|
199
|
+
// Handle validation errors
|
|
200
|
+
console.error('Validation errors:', issues);
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
queries: { /* ... */ },
|
|
204
|
+
mutations: { /* ... */ }
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 📤 File Upload Example
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
const api = createApiClient({
|
|
212
|
+
baseURL: 'https://api.example.com',
|
|
213
|
+
mutations: {
|
|
214
|
+
uploadImage: {
|
|
215
|
+
method: 'POST',
|
|
216
|
+
path: '/upload',
|
|
217
|
+
isMultipart: true, // Enable multipart/form-data
|
|
218
|
+
response: z.object({
|
|
219
|
+
url: z.string()
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// In component
|
|
226
|
+
const { mutate, uploadProgress } = api.mutation.uploadImage({
|
|
227
|
+
onUploadProgress: (progress) => {
|
|
228
|
+
console.log(`Upload progress: ${progress}%`);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
async function handleUpload(file: File) {
|
|
233
|
+
await mutate({ file });
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## 📝 License
|
|
238
|
+
|
|
239
|
+
MIT
|
|
240
|
+
|
|
241
|
+
## 👤 Author
|
|
242
|
+
|
|
243
|
+
MelvishNiz - [GitHub](https://github.com/MelvishNiz)
|
package/dist/core/client.d.ts
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
import { ApiClientOptions, ApiMutation, ApiQuery, Infer, MutationResult, QueryResult, UseMutationOptions, UseQueryOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a type-safe API client with query and mutation hooks for Vue 3
|
|
4
|
+
* @template Q - Record of query endpoint definitions
|
|
5
|
+
* @template M - Record of mutation endpoint definitions
|
|
6
|
+
* @param {ApiClientOptions<Q, M>} options - Configuration options for the API client
|
|
7
|
+
* @returns {Object} API client with query and mutation hooks
|
|
8
|
+
* @example
|
|
9
|
+
* import { createApiClient } from 'vue-api-kit';
|
|
10
|
+
* import { z } from 'zod';
|
|
11
|
+
*
|
|
12
|
+
* const api = createApiClient({
|
|
13
|
+
* baseURL: 'https://jsonplaceholder.typicode.com',
|
|
14
|
+
* queries: {
|
|
15
|
+
* getUsers: {
|
|
16
|
+
* path: '/users',
|
|
17
|
+
* response: z.array(z.object({
|
|
18
|
+
* id: z.number(),
|
|
19
|
+
* name: z.string()
|
|
20
|
+
* }))
|
|
21
|
+
* }
|
|
22
|
+
* },
|
|
23
|
+
* mutations: {
|
|
24
|
+
* createUser: {
|
|
25
|
+
* method: 'POST',
|
|
26
|
+
* path: '/users',
|
|
27
|
+
* data: z.object({
|
|
28
|
+
* name: z.string(),
|
|
29
|
+
* email: z.string().email()
|
|
30
|
+
* }),
|
|
31
|
+
* response: z.object({
|
|
32
|
+
* id: z.number(),
|
|
33
|
+
* name: z.string(),
|
|
34
|
+
* email: z.string()
|
|
35
|
+
* })
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // In your Vue component:
|
|
41
|
+
* const { result, isLoading } = api.query.getUsers();
|
|
42
|
+
* const { mutate } = api.mutation.createUser();
|
|
43
|
+
*/
|
|
2
44
|
export declare function createApiClient<Q extends Record<string, ApiQuery>, M extends Record<string, ApiMutation>>(options: ApiClientOptions<Q, M>): {
|
|
3
|
-
query: { [K in keyof Q]: (options?: UseQueryOptions<Infer<Q[K]["params"]>>) => QueryResult<Infer<Q[K]["response"]>>; };
|
|
4
|
-
mutation: { [K_1 in keyof M]: (options?: UseMutationOptions) => MutationResult<Infer<M[K_1]["response"]>, Infer<M[K_1]["data"]>>; };
|
|
45
|
+
query: { [K in keyof Q]: (options?: UseQueryOptions<Infer<Q[K]["params"]>, Infer<Q[K]["response"]>>) => QueryResult<Infer<Q[K]["response"]>>; };
|
|
46
|
+
mutation: { [K_1 in keyof M]: (options?: UseMutationOptions<Infer<M[K_1]["response"]>>) => MutationResult<Infer<M[K_1]["response"]>, Infer<M[K_1]["data"]>>; };
|
|
5
47
|
};
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,15 +1,52 @@
|
|
|
1
|
-
import { InternalAxiosRequestConfig } from 'axios';
|
|
1
|
+
import { AxiosError, InternalAxiosRequestConfig } from 'axios';
|
|
2
2
|
import { Ref } from 'vue';
|
|
3
|
-
import { ZodType } from 'zod';
|
|
3
|
+
import { ZodError, ZodType } from 'zod';
|
|
4
4
|
import { $ZodIssue } from 'zod/v4/core';
|
|
5
|
+
/**
|
|
6
|
+
* HTTP methods supported by the API client
|
|
7
|
+
* @example
|
|
8
|
+
* const method: HTTPMethod = "GET";
|
|
9
|
+
*/
|
|
5
10
|
export type HTTPMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
11
|
+
/**
|
|
12
|
+
* Infer TypeScript type from Zod schema
|
|
13
|
+
* @template T - Zod schema type
|
|
14
|
+
* @example
|
|
15
|
+
* const userSchema = z.object({ id: z.number(), name: z.string() });
|
|
16
|
+
* type User = Infer<typeof userSchema>; // { id: number; name: string }
|
|
17
|
+
*/
|
|
6
18
|
export type Infer<T> = T extends ZodType<infer U> ? U : any;
|
|
19
|
+
/**
|
|
20
|
+
* Defines a query (GET request) endpoint configuration
|
|
21
|
+
* @template TParams - Zod schema for query parameters
|
|
22
|
+
* @template TResponse - Zod schema for response data
|
|
23
|
+
* @example
|
|
24
|
+
* const getUsers: ApiQuery = {
|
|
25
|
+
* method: "GET",
|
|
26
|
+
* path: "/users",
|
|
27
|
+
* params: z.object({ page: z.number() }),
|
|
28
|
+
* response: z.array(z.object({ id: z.number(), name: z.string() }))
|
|
29
|
+
* };
|
|
30
|
+
*/
|
|
7
31
|
export interface ApiQuery<TParams extends ZodType<any> | undefined = ZodType<any> | undefined, TResponse extends ZodType<any> | undefined = ZodType<any> | undefined> {
|
|
8
32
|
method?: Extract<HTTPMethod, "GET">;
|
|
9
33
|
path: string;
|
|
10
34
|
params?: TParams;
|
|
11
35
|
response?: TResponse;
|
|
12
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Defines a mutation (POST, PUT, PATCH, DELETE) endpoint configuration
|
|
39
|
+
* @template TData - Zod schema for request body
|
|
40
|
+
* @template TResponse - Zod schema for response data
|
|
41
|
+
* @template TParams - Zod schema for path/query parameters
|
|
42
|
+
* @example
|
|
43
|
+
* const createUser: ApiMutation = {
|
|
44
|
+
* method: "POST",
|
|
45
|
+
* path: "/users",
|
|
46
|
+
* data: z.object({ name: z.string(), email: z.string().email() }),
|
|
47
|
+
* response: z.object({ id: z.number(), name: z.string(), email: z.string() })
|
|
48
|
+
* };
|
|
49
|
+
*/
|
|
13
50
|
export interface ApiMutation<TData extends ZodType<any> | undefined = ZodType<any> | undefined, TResponse extends ZodType<any> | undefined = ZodType<any> | undefined, TParams extends ZodType<any> | undefined = ZodType<any> | undefined> {
|
|
14
51
|
method: HTTPMethod;
|
|
15
52
|
path: string;
|
|
@@ -18,14 +55,29 @@ export interface ApiMutation<TData extends ZodType<any> | undefined = ZodType<an
|
|
|
18
55
|
response?: TResponse;
|
|
19
56
|
isMultipart?: boolean;
|
|
20
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Configuration options for creating an API client
|
|
60
|
+
* @template Q - Record of query endpoint definitions
|
|
61
|
+
* @template M - Record of mutation endpoint definitions
|
|
62
|
+
* @example
|
|
63
|
+
* const options: ApiClientOptions = {
|
|
64
|
+
* baseURL: "https://api.example.com",
|
|
65
|
+
* headers: { Authorization: "Bearer token" },
|
|
66
|
+
* queries: { getUsers: { path: "/users" } },
|
|
67
|
+
* mutations: { createUser: { method: "POST", path: "/users" } },
|
|
68
|
+
* onErrorRequest: (error) => console.error(error.message)
|
|
69
|
+
* };
|
|
70
|
+
*/
|
|
21
71
|
export interface ApiClientOptions<Q extends Record<string, ApiQuery> = Record<string, ApiQuery>, M extends Record<string, ApiMutation> = Record<string, ApiMutation>> {
|
|
22
72
|
baseURL: string;
|
|
23
73
|
headers?: Record<string, string>;
|
|
24
74
|
withCredentials?: boolean;
|
|
25
75
|
queries?: Q;
|
|
26
76
|
mutations?: M;
|
|
27
|
-
|
|
28
|
-
|
|
77
|
+
onBeforeRequest?: (config: InternalAxiosRequestConfig<any>) => Promise<any> | any;
|
|
78
|
+
onStartRequest?: () => Promise<void>;
|
|
79
|
+
onFinishRequest?: () => Promise<void>;
|
|
80
|
+
onErrorRequest?: (error: {
|
|
29
81
|
message: string;
|
|
30
82
|
status?: number;
|
|
31
83
|
code?: string;
|
|
@@ -33,31 +85,76 @@ export interface ApiClientOptions<Q extends Record<string, ApiQuery> = Record<st
|
|
|
33
85
|
}) => void;
|
|
34
86
|
onZodError?: (issues: Omit<$ZodIssue, "input">[]) => void;
|
|
35
87
|
}
|
|
36
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Options for configuring a query hook
|
|
90
|
+
* @template TParams - Type of query parameters
|
|
91
|
+
* @template TResult - Type of result data
|
|
92
|
+
* @example
|
|
93
|
+
* const options: UseQueryOptions = {
|
|
94
|
+
* params: { page: 1 },
|
|
95
|
+
* loadOnMount: true,
|
|
96
|
+
* debounce: 300,
|
|
97
|
+
* onResult: (data) => console.log(data),
|
|
98
|
+
* onError: (error) => console.error(error)
|
|
99
|
+
* };
|
|
100
|
+
*/
|
|
101
|
+
export interface UseQueryOptions<TParams = any, TResult = any> {
|
|
37
102
|
params?: TParams;
|
|
38
103
|
loadOnMount?: boolean;
|
|
39
104
|
debounce?: number;
|
|
40
|
-
onResult?: (
|
|
41
|
-
onError?: (error:
|
|
105
|
+
onResult?: (result: TResult) => void;
|
|
106
|
+
onError?: (error: AxiosError | ZodError | Error) => void;
|
|
42
107
|
onZodError?: (issues: Omit<$ZodIssue, "input">[]) => void;
|
|
43
108
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Options for configuring a mutation hook
|
|
111
|
+
* @template TResult - Type of result data
|
|
112
|
+
* @example
|
|
113
|
+
* const options: UseMutationOptions = {
|
|
114
|
+
* onResult: (data) => console.log("Success:", data),
|
|
115
|
+
* onError: (error) => console.error("Error:", error),
|
|
116
|
+
* onUploadProgress: (progress) => console.log(`Upload: ${progress}%`)
|
|
117
|
+
* };
|
|
118
|
+
*/
|
|
119
|
+
export interface UseMutationOptions<TResult = any> {
|
|
120
|
+
onResult?: (result: TResult) => void;
|
|
121
|
+
onError?: (error: AxiosError | ZodError | Error) => void;
|
|
47
122
|
onZodError?: (issues: Omit<$ZodIssue, "input">[]) => void;
|
|
48
123
|
onUploadProgress?: (progress: number) => void;
|
|
49
124
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Return type from a query hook
|
|
127
|
+
* @template TResult - Type of result data
|
|
128
|
+
* @example
|
|
129
|
+
* const { result, isLoading, errorMessage, refetch } = useGetUsers();
|
|
130
|
+
* // result.value contains the data
|
|
131
|
+
* // isLoading.value indicates loading state
|
|
132
|
+
* // errorMessage.value contains any error message
|
|
133
|
+
* // refetch() to manually trigger a new request
|
|
134
|
+
*/
|
|
135
|
+
export interface QueryResult<TResult> {
|
|
136
|
+
result: Ref<TResult | undefined>;
|
|
137
|
+
errorMessage: Ref<string | undefined>;
|
|
53
138
|
zodErrors: Ref<Omit<$ZodIssue, "input">[] | undefined>;
|
|
54
139
|
isLoading: Ref<boolean>;
|
|
55
140
|
isDone: Ref<boolean>;
|
|
56
141
|
refetch: () => Promise<void>;
|
|
57
142
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Return type from a mutation hook
|
|
145
|
+
* @template TResult - Type of result data
|
|
146
|
+
* @template TData - Type of mutation input data
|
|
147
|
+
* @example
|
|
148
|
+
* const { mutate, isLoading, result, errorMessage } = useCreateUser();
|
|
149
|
+
* // Call mutate() to trigger the mutation
|
|
150
|
+
* await mutate({ name: "John", email: "john@example.com" });
|
|
151
|
+
* // result.value contains the response
|
|
152
|
+
* // isLoading.value indicates loading state
|
|
153
|
+
* // uploadProgress.value shows upload progress (0-100)
|
|
154
|
+
*/
|
|
155
|
+
export interface MutationResult<TResult, TData> {
|
|
156
|
+
result: Ref<TResult | undefined>;
|
|
157
|
+
errorMessage: Ref<string | undefined>;
|
|
61
158
|
zodErrors: Ref<Omit<$ZodIssue, "input">[] | undefined>;
|
|
62
159
|
isLoading: Ref<boolean>;
|
|
63
160
|
isDone: Ref<boolean>;
|