vue-api-kit 1.8.1 → 1.10.1

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 CHANGED
@@ -234,6 +234,7 @@ async function handleSubmit() {
234
234
  - ✅ **Auto Loading States**: Built-in loading, error, and success states
235
235
  - ✅ **POST Queries**: Support for both GET and POST methods in queries for complex data retrieval
236
236
  - ✅ **Modular APIs**: Merge queries and mutations from separate files with full type safety
237
+ - ✅ **Multi-Level Nesting**: Organize queries and mutations in nested structures with full type safety
237
238
  - ✅ **File Upload**: Support for multipart/form-data in mutations
238
239
  - ✅ **Path Parameters**: Automatic path parameter replacement
239
240
  - ✅ **Debouncing**: Built-in request debouncing
@@ -243,6 +244,164 @@ async function handleSubmit() {
243
244
  - ✅ **Fully Typed**: Complete type inference for params, data, and response
244
245
  - ✅ **Tree-Shakeable**: Only bundles what you use
245
246
 
247
+ ## 🏗️ Multi-Level Nested Structure
248
+
249
+ Organize your API endpoints in a hierarchical structure for better code organization and maintainability.
250
+
251
+ ### Basic Nested Structure
252
+
253
+ ```typescript
254
+ import { createApiClient, defineQuery, defineMutation } from 'vue-api-kit';
255
+ import { z } from 'zod';
256
+
257
+ const api = createApiClient({
258
+ baseURL: 'https://api.example.com',
259
+
260
+ queries: {
261
+ // Organize queries by resource
262
+ users: {
263
+ getAll: defineQuery({
264
+ path: '/users',
265
+ response: z.array(z.object({
266
+ id: z.number(),
267
+ name: z.string()
268
+ }))
269
+ }),
270
+ getById: defineQuery({
271
+ path: '/users/{id}',
272
+ params: z.object({ id: z.number() }),
273
+ response: z.object({
274
+ id: z.number(),
275
+ name: z.string()
276
+ })
277
+ }),
278
+ search: defineQuery({
279
+ method: 'POST',
280
+ path: '/users/search',
281
+ data: z.object({ query: z.string() }),
282
+ response: z.array(z.object({ id: z.number(), name: z.string() }))
283
+ })
284
+ },
285
+ posts: {
286
+ getAll: defineQuery({
287
+ path: '/posts',
288
+ response: z.array(z.object({ id: z.number(), title: z.string() }))
289
+ }),
290
+ getById: defineQuery({
291
+ path: '/posts/{id}',
292
+ params: z.object({ id: z.number() }),
293
+ response: z.object({ id: z.number(), title: z.string() })
294
+ })
295
+ }
296
+ },
297
+
298
+ mutations: {
299
+ users: {
300
+ create: defineMutation({
301
+ method: 'POST',
302
+ path: '/users',
303
+ data: z.object({ name: z.string(), email: z.string().email() }),
304
+ response: z.object({ id: z.number(), name: z.string() })
305
+ }),
306
+ update: defineMutation({
307
+ method: 'PUT',
308
+ path: '/users/{id}',
309
+ params: z.object({ id: z.number() }),
310
+ data: z.object({ name: z.string() }),
311
+ response: z.object({ id: z.number(), name: z.string() })
312
+ }),
313
+ delete: defineMutation({
314
+ method: 'DELETE',
315
+ path: '/users/{id}',
316
+ params: z.object({ id: z.number() })
317
+ })
318
+ }
319
+ }
320
+ });
321
+
322
+ // Usage in components:
323
+ const { result, isLoading } = api.query.users.getAll();
324
+ const { mutate } = api.mutation.users.create();
325
+ ```
326
+
327
+ ### Deep Nesting
328
+
329
+ You can nest as deeply as needed for complex API structures:
330
+
331
+ ```typescript
332
+ const api = createApiClient({
333
+ baseURL: 'https://api.example.com',
334
+
335
+ queries: {
336
+ api: {
337
+ v1: {
338
+ admin: {
339
+ users: {
340
+ list: defineQuery({ path: '/api/v1/admin/users' }),
341
+ search: defineQuery({
342
+ method: 'POST',
343
+ path: '/api/v1/admin/users/search'
344
+ })
345
+ },
346
+ reports: {
347
+ daily: defineQuery({ path: '/api/v1/admin/reports/daily' }),
348
+ monthly: defineQuery({ path: '/api/v1/admin/reports/monthly' })
349
+ }
350
+ },
351
+ public: {
352
+ posts: {
353
+ list: defineQuery({ path: '/api/v1/public/posts' })
354
+ }
355
+ }
356
+ }
357
+ }
358
+ }
359
+ });
360
+
361
+ // Access deeply nested endpoints:
362
+ api.query.api.v1.admin.users.list()
363
+ api.query.api.v1.admin.reports.daily()
364
+ api.query.api.v1.public.posts.list()
365
+ ```
366
+
367
+ ### Mixed Flat and Nested Structure
368
+
369
+ You can combine flat and nested structures as needed:
370
+
371
+ ```typescript
372
+ const api = createApiClient({
373
+ baseURL: 'https://api.example.com',
374
+
375
+ queries: {
376
+ // Flat queries
377
+ getStatus: defineQuery({ path: '/status' }),
378
+ getHealth: defineQuery({ path: '/health' }),
379
+
380
+ // Nested queries
381
+ users: {
382
+ getAll: defineQuery({ path: '/users' }),
383
+ getById: defineQuery({ path: '/users/{id}' })
384
+ },
385
+ posts: {
386
+ getAll: defineQuery({ path: '/posts' })
387
+ }
388
+ }
389
+ });
390
+
391
+ // Both flat and nested work together:
392
+ api.query.getStatus() // Flat
393
+ api.query.users.getAll() // Nested
394
+ ```
395
+
396
+ ### Benefits
397
+
398
+ - **Better Organization**: Group related endpoints together
399
+ - **Improved Readability**: Clear hierarchical structure reflects your API design
400
+ - **Namespace Separation**: Prevent naming conflicts (e.g., `users.create` vs `posts.create`)
401
+ - **Scalability**: Easy to add new endpoints without cluttering the root level
402
+ - **Type Safety**: Full TypeScript inference throughout the nested structure
403
+ - **Backward Compatible**: Works alongside existing flat structure
404
+
246
405
  ## 🔧 Advanced Configuration
247
406
 
248
407
  ```typescript
@@ -539,6 +698,99 @@ export const api = createApiClient({
539
698
  // api.mutation.createPost ✓ Fully typed
540
699
  ```
541
700
 
701
+ ### Nested Structure with Modular APIs
702
+
703
+ You can also use nested structures with modular API definitions:
704
+
705
+ **user-api.ts** - User module with nested structure
706
+ ```typescript
707
+ import { z, defineQuery, defineMutation } from 'vue-api-kit';
708
+
709
+ export const userApi = {
710
+ queries: {
711
+ users: {
712
+ getAll: defineQuery({
713
+ path: '/users',
714
+ response: z.array(z.object({ id: z.number(), name: z.string() }))
715
+ }),
716
+ getById: defineQuery({
717
+ path: '/users/{id}',
718
+ params: z.object({ id: z.number() }),
719
+ response: z.object({ id: z.number(), name: z.string() })
720
+ })
721
+ }
722
+ },
723
+ mutations: {
724
+ users: {
725
+ create: defineMutation({
726
+ method: 'POST',
727
+ path: '/users',
728
+ data: z.object({ name: z.string() })
729
+ }),
730
+ update: defineMutation({
731
+ method: 'PUT',
732
+ path: '/users/{id}',
733
+ params: z.object({ id: z.number() }),
734
+ data: z.object({ name: z.string() })
735
+ })
736
+ }
737
+ }
738
+ };
739
+ ```
740
+
741
+ **post-api.ts** - Post module with nested structure
742
+ ```typescript
743
+ import { z, defineQuery, defineMutation } from 'vue-api-kit';
744
+
745
+ export const postApi = {
746
+ queries: {
747
+ posts: {
748
+ getAll: defineQuery({
749
+ path: '/posts',
750
+ response: z.array(z.object({ id: z.number(), title: z.string() }))
751
+ }),
752
+ getById: defineQuery({
753
+ path: '/posts/{id}',
754
+ params: z.object({ id: z.number() }),
755
+ response: z.object({ id: z.number(), title: z.string() })
756
+ })
757
+ }
758
+ },
759
+ mutations: {
760
+ posts: {
761
+ create: defineMutation({
762
+ method: 'POST',
763
+ path: '/posts',
764
+ data: z.object({ title: z.string(), content: z.string() })
765
+ })
766
+ }
767
+ }
768
+ };
769
+ ```
770
+
771
+ **api.ts** - Merge nested structures
772
+ ```typescript
773
+ import { createApiClient, mergeQueries, mergeMutations } from 'vue-api-kit';
774
+ import { userApi } from './user-api';
775
+ import { postApi } from './post-api';
776
+
777
+ export const api = createApiClient({
778
+ baseURL: 'https://api.example.com',
779
+
780
+ // Merge nested queries from modules
781
+ queries: mergeQueries(userApi.queries, postApi.queries),
782
+
783
+ // Merge nested mutations from modules
784
+ mutations: mergeMutations(userApi.mutations, postApi.mutations)
785
+ });
786
+
787
+ // Usage with nested structure:
788
+ api.query.users.getAll() // ✓ Fully typed
789
+ api.query.posts.getById() // ✓ Fully typed
790
+ api.mutation.users.create() // ✓ Fully typed
791
+ api.mutation.posts.create() // ✓ Fully typed
792
+ ```
793
+
542
794
  ### Benefits of Modular Approach
543
795
 
544
796
  - **Separation of Concerns**: Keep related API endpoints together in dedicated files
@@ -682,3 +934,4 @@ MIT
682
934
  ## 👤 Author
683
935
 
684
936
  MelvishNiz - [GitHub](https://github.com/MelvishNiz)
937
+
@@ -1,4 +1,4 @@
1
- import { ApiClientOptions, ApiMutation, ApiQuery, Infer, MutationResult, QueryResult, UseMutationOptions, UseQueryOptions } from './types';
1
+ import { ApiClientOptions, ApiMutation, ApiQuery, QueryHooksFromDefinitions, MutationHooksFromDefinitions, NestedStructure } from './types';
2
2
  /**
3
3
  * Creates a type-safe API client with query and mutation hooks for Vue 3
4
4
  * @template Q - Record of query endpoint definitions
@@ -41,7 +41,7 @@ import { ApiClientOptions, ApiMutation, ApiQuery, Infer, MutationResult, QueryRe
41
41
  * const { result, isLoading } = api.query.getUsers();
42
42
  * const { mutate } = api.mutation.createUser();
43
43
  */
44
- export declare function createApiClient<Q extends Record<string, ApiQuery>, M extends Record<string, ApiMutation>>(options: ApiClientOptions<Q, M>): {
45
- query: { [K in keyof Q]: (options?: UseQueryOptions<Infer<Q[K]["params"]>, Infer<Q[K]["data"]>, 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"]>, Infer<M[K_1]["params"]>>; };
44
+ export declare function createApiClient<Q extends Record<string, NestedStructure<ApiQuery>>, M extends Record<string, NestedStructure<ApiMutation>>>(options: ApiClientOptions<Q, M>): {
45
+ query: QueryHooksFromDefinitions<Q>;
46
+ mutation: MutationHooksFromDefinitions<M>;
47
47
  };
@@ -66,10 +66,36 @@ export interface ApiMutation<TData extends ZodType<any> | undefined = ZodType<an
66
66
  isMultipart?: boolean;
67
67
  onBeforeRequest?: (config: InternalAxiosRequestConfig<any>) => Promise<any> | void | any;
68
68
  }
69
+ /**
70
+ * Recursive type to represent nested query or mutation structure
71
+ */
72
+ export type NestedStructure<T> = T | {
73
+ [key: string]: NestedStructure<T>;
74
+ };
75
+ /**
76
+ * Extract query hook function from ApiQuery definition
77
+ */
78
+ export type QueryHookFromDefinition<Q extends ApiQuery> = (options?: UseQueryOptions<Infer<Q["params"]>, Infer<Q["data"]>, Infer<Q["response"]>>) => QueryResult<Infer<Q["response"]>>;
79
+ /**
80
+ * Extract mutation hook function from ApiMutation definition
81
+ */
82
+ export type MutationHookFromDefinition<M extends ApiMutation> = (options?: UseMutationOptions<Infer<M["response"]>>) => MutationResult<Infer<M["response"]>, Infer<M["data"]>, Infer<M["params"]>>;
83
+ /**
84
+ * Recursively transform nested query definitions into query hooks
85
+ */
86
+ export type QueryHooksFromDefinitions<Q> = {
87
+ [K in keyof Q]: Q[K] extends ApiQuery ? QueryHookFromDefinition<Q[K]> : Q[K] extends Record<string, NestedStructure<ApiQuery>> ? QueryHooksFromDefinitions<Q[K]> : never;
88
+ };
89
+ /**
90
+ * Recursively transform nested mutation definitions into mutation hooks
91
+ */
92
+ export type MutationHooksFromDefinitions<M> = {
93
+ [K in keyof M]: M[K] extends ApiMutation ? MutationHookFromDefinition<M[K]> : M[K] extends Record<string, NestedStructure<ApiMutation>> ? MutationHooksFromDefinitions<M[K]> : never;
94
+ };
69
95
  /**
70
96
  * Configuration options for creating an API client
71
- * @template Q - Record of query endpoint definitions
72
- * @template M - Record of mutation endpoint definitions
97
+ * @template Q - Record of query endpoint definitions (can be nested)
98
+ * @template M - Record of mutation endpoint definitions (can be nested)
73
99
  * @example
74
100
  * const options: ApiClientOptions = {
75
101
  * baseURL: "https://api.example.com",
@@ -80,8 +106,19 @@ export interface ApiMutation<TData extends ZodType<any> | undefined = ZodType<an
80
106
  * mutations: { createUser: { method: "POST", path: "/users" } },
81
107
  * onErrorRequest: (error) => console.error(error.message)
82
108
  * };
109
+ * @example
110
+ * // Nested structure
111
+ * const options: ApiClientOptions = {
112
+ * baseURL: "https://api.example.com",
113
+ * queries: {
114
+ * users: {
115
+ * getAll: { path: "/users" },
116
+ * getById: { path: "/users/{id}" }
117
+ * }
118
+ * }
119
+ * };
83
120
  */
84
- export interface ApiClientOptions<Q extends Record<string, ApiQuery> = Record<string, ApiQuery>, M extends Record<string, ApiMutation> = Record<string, ApiMutation>> {
121
+ export interface ApiClientOptions<Q extends Record<string, NestedStructure<ApiQuery>> = Record<string, NestedStructure<ApiQuery>>, M extends Record<string, NestedStructure<ApiMutation>> = Record<string, NestedStructure<ApiMutation>>> {
85
122
  baseURL: string;
86
123
  headers?: Record<string, string>;
87
124
  withCredentials?: boolean;
@@ -97,6 +134,7 @@ export interface ApiClientOptions<Q extends Record<string, ApiQuery> = Record<st
97
134
  status?: number;
98
135
  code?: string;
99
136
  data?: any;
137
+ url?: string;
100
138
  }) => void;
101
139
  onZodError?: (issues: Omit<$ZodIssue, "input">[]) => void;
102
140
  }
package/dist/index.js CHANGED
@@ -1,232 +1,254 @@
1
1
  import { ZodError as S } from "zod";
2
- import * as U from "zod";
3
- import L, { AxiosError as F } from "axios";
4
- import { AxiosError as K } from "axios";
5
- import { nextTick as T, ref as m, onMounted as k, watch as Z, onBeforeUnmount as x } from "vue";
6
- import { debounce as N } from "lodash-es";
7
- function V(s) {
8
- const R = L.create({
9
- baseURL: s.baseURL,
2
+ import * as H from "zod";
3
+ import N, { AxiosError as F } from "axios";
4
+ import { AxiosError as ae } from "axios";
5
+ import { nextTick as $, ref as R, onMounted as U, watch as _, onBeforeUnmount as I } from "vue";
6
+ import { debounce as Q } from "lodash-es";
7
+ function z(e) {
8
+ return e && typeof e == "object" && e !== null && typeof e.path == "string";
9
+ }
10
+ function V(e) {
11
+ return e && typeof e == "object" && e !== null && typeof e.path == "string" && typeof e.method == "string";
12
+ }
13
+ function K(e) {
14
+ const y = N.create({
15
+ baseURL: e.baseURL,
10
16
  headers: {
11
17
  "Content-Type": "application/json",
12
18
  Accept: "application/json",
13
- ...s.headers
19
+ ...e.headers
14
20
  },
15
- withCredentials: s.withCredentials ?? !1,
16
- withXSRFToken: s.withXSRFToken ?? !1
21
+ withCredentials: e.withCredentials ?? !1,
22
+ withXSRFToken: e.withXSRFToken ?? !1
17
23
  });
18
- let C = !1, j = null;
19
- s.onBeforeRequest && R.interceptors.request.use(
20
- async (e) => {
24
+ let P = !1, b = null;
25
+ e.onBeforeRequest && y.interceptors.request.use(
26
+ async (r) => {
21
27
  try {
22
- return await s.onBeforeRequest(e) || e;
23
- } catch (r) {
24
- return Promise.reject(r);
28
+ return await e.onBeforeRequest(r) || r;
29
+ } catch (i) {
30
+ return Promise.reject(i);
25
31
  }
26
32
  },
27
- (e) => Promise.reject(e)
28
- ), s.onStartRequest && R.interceptors.request.use(
29
- async (e) => {
33
+ (r) => Promise.reject(r)
34
+ ), e.onStartRequest && y.interceptors.request.use(
35
+ async (r) => {
30
36
  try {
31
- return await s.onStartRequest(), e;
32
- } catch (r) {
33
- return Promise.reject(r);
37
+ return await e.onStartRequest(), r;
38
+ } catch (i) {
39
+ return Promise.reject(i);
34
40
  }
35
41
  },
36
- (e) => Promise.reject(e)
37
- ), s.onFinishRequest && R.interceptors.response.use(
38
- (e) => (s.onFinishRequest(), e),
39
- (e) => (s.onFinishRequest(), Promise.reject(e))
40
- ), R.interceptors.request.use((e) => {
41
- if (!e.url) return e;
42
- const r = (a) => {
43
- if (a)
44
- for (const [t, p] of Object.entries(a)) {
45
- const f = `{${t}}`;
46
- e.url.includes(f) && (e.url = e.url.replace(
47
- f,
48
- encodeURIComponent(String(p))
49
- ), delete a[t]);
42
+ (r) => Promise.reject(r)
43
+ ), e.onFinishRequest && y.interceptors.response.use(
44
+ (r) => (e.onFinishRequest(), r),
45
+ (r) => (e.onFinishRequest(), Promise.reject(r))
46
+ ), y.interceptors.request.use((r) => {
47
+ if (!r.url) return r;
48
+ const i = (m) => {
49
+ if (m)
50
+ for (const [d, t] of Object.entries(m)) {
51
+ const n = `{${d}}`;
52
+ r.url.includes(n) && (r.url = r.url.replace(
53
+ n,
54
+ encodeURIComponent(String(t))
55
+ ), delete m[d]);
50
56
  }
51
57
  };
52
- return e.method !== "get" && e.data?.params && r(e.data.params), r(e.params), e;
53
- }), s.csrfRefreshEndpoint && R.interceptors.response.use(
54
- (e) => e,
55
- async (e) => {
56
- const r = e.config;
57
- if (r?.url === s.csrfRefreshEndpoint)
58
- return Promise.reject(e);
59
- if (e.response && (e.response.status === 403 || e.response.status === 419) && !r?._retry) {
60
- r._retry = !0;
58
+ return r.method !== "get" && r.data?.params && i(r.data.params), i(r.params), r;
59
+ }), e.csrfRefreshEndpoint && y.interceptors.response.use(
60
+ (r) => r,
61
+ async (r) => {
62
+ const i = r.config;
63
+ if (i?.url === e.csrfRefreshEndpoint)
64
+ return Promise.reject(r);
65
+ if (r.response && (r.response.status === 403 || r.response.status === 419) && !i?._retry) {
66
+ i._retry = !0;
61
67
  try {
62
- return C && j ? await j : (C = !0, j = R.get(s.csrfRefreshEndpoint).then(() => {
63
- C = !1, j = null;
64
- }), await j), R.request(r);
65
- } catch (a) {
66
- return C = !1, j = null, Promise.reject(a);
68
+ return P && b ? await b : (P = !0, b = y.get(e.csrfRefreshEndpoint).then(() => {
69
+ P = !1, b = null;
70
+ }), await b), y.request(i);
71
+ } catch (m) {
72
+ return P = !1, b = null, Promise.reject(m);
67
73
  }
68
74
  }
69
- return Promise.reject(e);
75
+ return Promise.reject(r);
70
76
  }
71
- ), R.interceptors.response.use(
72
- (e) => e,
73
- (e) => (T(() => {
74
- e.code;
75
- }), Promise.reject(e))
77
+ ), y.interceptors.response.use(
78
+ (r) => r,
79
+ (r) => ($(() => {
80
+ r.code;
81
+ }), Promise.reject(r))
76
82
  );
77
- const P = s.queries ?? {}, M = {};
78
- for (const e in P) {
79
- const r = P[e];
80
- r && (M[e] = (a) => {
81
- let t;
82
- a && typeof a == "object" && ("loadOnMount" in a || "debounce" in a || "onResult" in a || "onError" in a || "onZodError" in a || "onBeforeRequest" in a || "data" in a ? t = a : t = { params: a });
83
- const p = m(), f = m(), g = m(), E = m(!1), y = m(!1), A = m(!0);
84
- let b = new AbortController();
85
- const i = () => {
86
- b?.abort(), b = new AbortController();
87
- }, l = async () => {
88
- E.value && i(), E.value = !0, f.value = void 0;
89
- try {
90
- r.params && t?.params && r.params.parse(t.params);
91
- let o = t?.data;
92
- r.data && o && r.data.parse(o);
93
- const u = {
94
- method: r.method ?? "GET",
95
- url: r.path,
96
- params: t?.params,
97
- signal: b.signal
83
+ function D(r) {
84
+ const i = {};
85
+ for (const m in r) {
86
+ const d = r[m];
87
+ if (d)
88
+ if (z(d)) {
89
+ const t = d;
90
+ i[m] = (n) => {
91
+ let a;
92
+ n && typeof n == "object" && ("loadOnMount" in n || "debounce" in n || "onResult" in n || "onError" in n || "onZodError" in n || "onBeforeRequest" in n || "data" in n ? a = n : a = { params: n });
93
+ const C = R(), g = R(), q = R(), j = R(!1), A = R(!1), B = R(!0);
94
+ let w = new AbortController();
95
+ const u = () => {
96
+ w?.abort(), w = new AbortController();
97
+ }, l = async () => {
98
+ j.value && u(), j.value = !0, g.value = void 0;
99
+ try {
100
+ t.params && a?.params && t.params.parse(a.params);
101
+ let s = a?.data;
102
+ t.data && s && t.data.parse(s);
103
+ const c = {
104
+ method: t.method ?? "GET",
105
+ url: t.path,
106
+ params: a?.params,
107
+ signal: w.signal
108
+ };
109
+ if (t.method === "POST" && s && (c.data = s), t.onBeforeRequest) {
110
+ const f = await t.onBeforeRequest(c);
111
+ f !== void 0 && Object.assign(c, f);
112
+ }
113
+ if (a?.onBeforeRequest) {
114
+ const f = await a.onBeforeRequest(c);
115
+ f !== void 0 && Object.assign(c, f);
116
+ }
117
+ const h = await y.request(c), o = t.response ? t.response.parse(h.data) : h.data;
118
+ C.value = o, a?.onResult?.(o);
119
+ } catch (s) {
120
+ if (s instanceof F) {
121
+ if (s.code !== "ERR_CANCELED") {
122
+ const c = s.config?.url, h = s.response?.data?.message || s.message || "An error occurred", o = s.response?.status, f = s.code, v = s.response?.data;
123
+ g.value = h, a?.onError?.(s), e.onErrorRequest?.({ message: h, status: o, code: f, data: v, url: c });
124
+ }
125
+ } else if (s instanceof S) {
126
+ q.value = s.issues || [];
127
+ const h = `Validation error: ${q.value.map(
128
+ (o) => `${o.path.join(".")}: ${o.message}`
129
+ ).join(", ")}`;
130
+ g.value = h, a?.onError?.(s), a?.onZodError?.(q.value), e.onErrorRequest?.({ message: h, code: "VALIDATION_ERROR" }), e.onZodError && e.onZodError(q.value);
131
+ } else {
132
+ const c = s.message || "An error occurred";
133
+ g.value = c, a?.onError?.(c), e.onErrorRequest?.({ message: c });
134
+ }
135
+ } finally {
136
+ j.value = !1, A.value = !0;
137
+ }
138
+ }, E = a?.debounce ? Q(l, a.debounce) : l;
139
+ let p = null;
140
+ return (a?.params || a?.data) && (U(() => {
141
+ p && p(), p = _(
142
+ () => JSON.stringify({ params: a.params, data: a.data }),
143
+ () => {
144
+ E();
145
+ },
146
+ { immediate: !1 }
147
+ );
148
+ }), I(() => {
149
+ p && p(), w?.abort();
150
+ })), (a?.loadOnMount === void 0 || a.loadOnMount) && !A.value && (B.value ? (B.value = !1, l()) : E()), { result: C, errorMessage: g, zodErrors: q, isLoading: j, isDone: A, refetch: l };
98
151
  };
99
- if (r.method === "POST" && o && (u.data = o), r.onBeforeRequest) {
100
- const c = await r.onBeforeRequest(u);
101
- c !== void 0 && Object.assign(u, c);
102
- }
103
- if (t?.onBeforeRequest) {
104
- const c = await t.onBeforeRequest(u);
105
- c !== void 0 && Object.assign(u, c);
106
- }
107
- const h = await R.request(u), n = r.response ? r.response.parse(h.data) : h.data;
108
- p.value = n, t?.onResult?.(n);
109
- } catch (o) {
110
- if (o instanceof F) {
111
- if (o.code !== "ERR_CANCELED") {
112
- const u = o.response?.data?.message || o.message || "An error occurred", h = o.response?.status, n = o.code, c = o.response?.data;
113
- f.value = u, t?.onError?.(o), s.onErrorRequest?.({ message: u, status: h, code: n, data: c });
114
- }
115
- } else if (o instanceof S) {
116
- g.value = o.issues || [];
117
- const h = `Validation error: ${g.value.map(
118
- (n) => `${n.path.join(".")}: ${n.message}`
119
- ).join(", ")}`;
120
- f.value = h, t?.onError?.(o), t?.onZodError?.(g.value), s.onErrorRequest?.({ message: h, code: "VALIDATION_ERROR" }), s.onZodError && s.onZodError(g.value);
121
- } else {
122
- const u = o.message || "An error occurred";
123
- f.value = u, t?.onError?.(u), s.onErrorRequest?.({ message: u });
124
- }
125
- } finally {
126
- E.value = !1, y.value = !0;
127
- }
128
- }, v = t?.debounce ? N(l, t.debounce) : l;
129
- let d = null;
130
- return (t?.params || t?.data) && (k(() => {
131
- d && d(), d = Z(
132
- () => JSON.stringify({ params: t.params, data: t.data }),
133
- () => {
134
- v();
135
- },
136
- { immediate: !1 }
137
- );
138
- }), x(() => {
139
- d && d(), b?.abort();
140
- })), (t?.loadOnMount === void 0 || t.loadOnMount) && !y.value && (A.value ? (A.value = !1, l()) : v()), { result: p, errorMessage: f, zodErrors: g, isLoading: E, isDone: y, refetch: l };
141
- });
152
+ } else typeof d == "object" && (i[m] = D(d));
153
+ }
154
+ return i;
142
155
  }
143
- const B = s.mutations ?? {}, D = {};
144
- for (const e in B) {
145
- const r = B[e];
146
- r && (D[e] = (a) => {
147
- const t = m(), p = m(), f = m(), g = m(!1), E = m(!1), y = m(0);
148
- return { result: t, errorMessage: p, zodErrors: f, isLoading: g, isDone: E, uploadProgress: y, mutate: async (b) => {
149
- if (!g.value) {
150
- g.value = !0, p.value = void 0, y.value = 0;
151
- try {
152
- const { data: i = {}, params: l } = b ?? {};
153
- let v = i ?? {}, d = {};
154
- if (r.isMultipart) {
155
- const n = new FormData();
156
- for (const [c, q] of Object.entries(i))
157
- q instanceof File || q instanceof Blob ? n.append(c, q) : Array.isArray(q) ? q.forEach((w) => {
158
- w instanceof File || w instanceof Blob ? n.append(c, w) : n.append(c, JSON.stringify(w));
159
- }) : typeof q == "object" && q !== null ? n.append(c, JSON.stringify(q)) : n.append(c, String(q));
160
- v = n, d["Content-Type"] = "multipart/form-data";
161
- } else r.data && r.data.parse(i);
162
- r.params && l && r.params.parse(l);
163
- const o = {
164
- method: r.method,
165
- url: r.path,
166
- data: v,
167
- params: l,
168
- headers: d,
169
- onUploadProgress: (n) => {
170
- if (n.total) {
171
- const c = Math.round(n.loaded * 100 / n.total);
172
- y.value = c, a?.onUploadProgress?.(c);
156
+ const L = e.queries ?? {}, T = D(L);
157
+ function k(r) {
158
+ const i = {};
159
+ for (const m in r) {
160
+ const d = r[m];
161
+ if (d)
162
+ if (V(d)) {
163
+ const t = d;
164
+ i[m] = (n) => {
165
+ const a = R(), C = R(), g = R(), q = R(!1), j = R(!1), A = R(0);
166
+ return { result: a, errorMessage: C, zodErrors: g, isLoading: q, isDone: j, uploadProgress: A, mutate: async (w) => {
167
+ if (!q.value) {
168
+ q.value = !0, C.value = void 0, A.value = 0;
169
+ try {
170
+ const { data: u = {}, params: l } = w ?? {};
171
+ let E = u ?? {}, p = {};
172
+ if (t.isMultipart) {
173
+ const o = new FormData();
174
+ for (const [f, v] of Object.entries(u))
175
+ v instanceof File || v instanceof Blob ? o.append(f, v) : Array.isArray(v) ? v.forEach((M) => {
176
+ M instanceof File || M instanceof Blob ? o.append(f, M) : o.append(f, JSON.stringify(M));
177
+ }) : typeof v == "object" && v !== null ? o.append(f, JSON.stringify(v)) : o.append(f, String(v));
178
+ E = o, p["Content-Type"] = "multipart/form-data";
179
+ } else t.data && t.data.parse(u);
180
+ t.params && l && t.params.parse(l);
181
+ const s = {
182
+ method: t.method,
183
+ url: t.path,
184
+ data: E,
185
+ params: l,
186
+ headers: p,
187
+ onUploadProgress: (o) => {
188
+ if (o.total) {
189
+ const f = Math.round(o.loaded * 100 / o.total);
190
+ A.value = f, n?.onUploadProgress?.(f);
191
+ }
192
+ }
193
+ };
194
+ if (t.onBeforeRequest) {
195
+ const o = await t.onBeforeRequest(s);
196
+ o !== void 0 && Object.assign(s, o);
197
+ }
198
+ if (n?.onBeforeRequest) {
199
+ const o = await n.onBeforeRequest(s);
200
+ o !== void 0 && Object.assign(s, o);
201
+ }
202
+ const c = await y.request(s), h = t.response ? t.response.parse(c.data) : c.data;
203
+ a.value = h, n?.onResult?.(h);
204
+ } catch (u) {
205
+ if (u instanceof F) {
206
+ const l = u.response?.data?.message || u.message || "An error occurred", E = u.response?.status, p = u.code;
207
+ C.value = l, n?.onError?.(u), e.onErrorRequest?.({ message: l, status: E, code: p });
208
+ } else if (u instanceof S) {
209
+ g.value = u.issues || [];
210
+ const E = `Validation error: ${g.value.map(
211
+ (p) => `${p.path.join(".")}: ${p.message}`
212
+ ).join(", ")}`;
213
+ C.value = E, n?.onError?.(u), n?.onZodError?.(g.value), e.onErrorRequest?.({ message: E, code: "VALIDATION_ERROR" }), e.onZodError && e.onZodError(g.value);
214
+ } else {
215
+ const l = u.message || "An error occurred";
216
+ C.value = l, n?.onError?.(u), e.onErrorRequest?.({ message: l });
217
+ }
218
+ } finally {
219
+ q.value = !1, j.value = !0;
173
220
  }
174
221
  }
175
- };
176
- if (r.onBeforeRequest) {
177
- const n = await r.onBeforeRequest(o);
178
- n !== void 0 && Object.assign(o, n);
179
- }
180
- if (a?.onBeforeRequest) {
181
- const n = await a.onBeforeRequest(o);
182
- n !== void 0 && Object.assign(o, n);
183
- }
184
- const u = await R.request(o), h = r.response ? r.response.parse(u.data) : u.data;
185
- t.value = h, a?.onResult?.(h);
186
- } catch (i) {
187
- if (i instanceof F) {
188
- const l = i.response?.data?.message || i.message || "An error occurred", v = i.response?.status, d = i.code;
189
- p.value = l, a?.onError?.(i), s.onErrorRequest?.({ message: l, status: v, code: d });
190
- } else if (i instanceof S) {
191
- f.value = i.issues || [];
192
- const v = `Validation error: ${f.value.map(
193
- (d) => `${d.path.join(".")}: ${d.message}`
194
- ).join(", ")}`;
195
- p.value = v, a?.onError?.(i), a?.onZodError?.(f.value), s.onErrorRequest?.({ message: v, code: "VALIDATION_ERROR" }), s.onZodError && s.onZodError(f.value);
196
- } else {
197
- const l = i.message || "An error occurred";
198
- p.value = l, a?.onError?.(i), s.onErrorRequest?.({ message: l });
199
- }
200
- } finally {
201
- g.value = !1, E.value = !0;
202
- }
203
- }
204
- } };
205
- });
222
+ } };
223
+ };
224
+ } else typeof d == "object" && (i[m] = k(d));
225
+ }
226
+ return i;
206
227
  }
228
+ const Z = e.mutations ?? {}, x = k(Z);
207
229
  return {
208
- query: M,
209
- mutation: D
230
+ query: T,
231
+ mutation: x
210
232
  };
211
233
  }
212
- function J(s) {
213
- return s;
234
+ function Y(e) {
235
+ return e;
214
236
  }
215
- function Q(s) {
216
- return s;
237
+ function O(e) {
238
+ return e;
217
239
  }
218
- function W(...s) {
219
- return Object.assign({}, ...s);
240
+ function ee(...e) {
241
+ return Object.assign({}, ...e);
220
242
  }
221
- function X(...s) {
222
- return Object.assign({}, ...s);
243
+ function re(...e) {
244
+ return Object.assign({}, ...e);
223
245
  }
224
246
  export {
225
- K as AxiosError,
226
- V as createApiClient,
227
- Q as defineMutation,
228
- J as defineQuery,
229
- X as mergeMutations,
230
- W as mergeQueries,
231
- U as z
247
+ ae as AxiosError,
248
+ K as createApiClient,
249
+ O as defineMutation,
250
+ Y as defineQuery,
251
+ re as mergeMutations,
252
+ ee as mergeQueries,
253
+ H as z
232
254
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vue-api-kit",
3
3
  "type": "module",
4
- "version": "1.8.1",
4
+ "version": "1.10.1",
5
5
  "description": "A powerful and flexible API client for Vue 3 applications, built with TypeScript and Zod for type-safe API interactions.",
6
6
  "keywords": [
7
7
  "vue3",