@ametie/vue-muza-use 0.4.10 โ†’ 0.5.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 CHANGED
@@ -13,18 +13,48 @@ A production-ready composable that eliminates boilerplate and solves the hard pr
13
13
 
14
14
  ## โœจ Features
15
15
 
16
+ **Core Features** (Get started in minutes):
16
17
  - ๐ŸŽฏ **Fully Type-Safe** โ€” End-to-end TypeScript support with strict typing for requests and responses
17
18
  - ๐Ÿ”„ **Smart Reactivity** โ€” Watch refs and automatically refetch when dependencies change
18
19
  - โฑ๏ธ **Built-in Debouncing** โ€” Perfect for search inputs and auto-save forms
19
20
  - ๐Ÿ›ก๏ธ **Race Condition Protection** โ€” Global abort controller cancels stale requests automatically
20
- - ๐Ÿ” **JWT Token Management** โ€” Automatic token refresh with request queueing on 401 responses
21
- - โ™ป๏ธ **Intelligent Retries** โ€” Lifecycle-aware retry logic that respects component unmounting
22
21
  - ๐Ÿ“Š **Auto-Polling** โ€” Built-in interval fetching with smart tab visibility detection
23
22
  - ๐Ÿงน **Zero Memory Leaks** โ€” Automatic cleanup of pending requests on component unmount
23
+
24
+ **Advanced Features** (When you need them):
25
+ - โ™ป๏ธ **Intelligent Retries** โ€” Lifecycle-aware retry logic that respects component unmounting
26
+ - ๐Ÿ” **JWT Token Management** โ€” Automatic token refresh with request queueing on 401 responses
24
27
  - ๐ŸŽ›๏ธ **Flexible Architecture** โ€” Bring your own Axios instance with full configuration control
25
28
 
26
29
  ---
27
30
 
31
+ ## ๐Ÿ“– Table of Contents
32
+
33
+ **Getting Started:**
34
+ - [Installation](#-installation)
35
+ - [Quick Start](#-quick-start)
36
+ - [Basic Usage](#-basic-usage)
37
+
38
+ **Core Features:**
39
+ - [Watch & Auto-Refetch](#watch--auto-refetch)
40
+ - [Polling](#polling-background-updates)
41
+ - [Error Handling](#error-handling)
42
+ - [Loading States](#loading-states)
43
+ - [Manual Data Updates](#manual-data-updates)
44
+
45
+ **Real-World Examples:**
46
+ - [Data Table with Pagination](#data-table-with-pagination--sorting)
47
+ - [Request Cancellation](#request-cancellation)
48
+
49
+ **Advanced:**
50
+ - [Custom Axios Instance](#-advanced-configuration)
51
+ - [Authentication & Tokens](#-authentication--token-management) *(Optional)*
52
+ - [API Reference](#-api-reference)
53
+
54
+ > ๐Ÿ’ก **New to the library?** Start with [Quick Start](#-quick-start), then explore [Basic Usage](#-basic-usage). Skip authentication until you need it!
55
+
56
+ ---
57
+
28
58
  ## ๐Ÿ“ฆ Installation
29
59
 
30
60
  ```bash
@@ -344,6 +374,108 @@ const { execute } = useApi('/analytics', {
344
374
 
345
375
  ---
346
376
 
377
+ ### Manual Data Updates
378
+
379
+ Use `setData` to manually update the data ref. Supports direct values or updater functions (like React's `setState`).
380
+
381
+ > ๐ŸŽ“ **When to use `setData`:**
382
+ > โœ… Adding/removing/updating items in arrays
383
+ > โœ… Local sorting/filtering (without refetching)
384
+ > โœ… Transform data in `onSuccess` (adding computed fields)
385
+ >
386
+ > **When to use `computed` instead:**
387
+ > โœ… Completely changing data structure (e.g., API format โ†’ App format)
388
+ > โœ… Extracting nested data that changes the return type
389
+ > โœ… Complex transformations that depend on other refs
390
+
391
+ #### Add/Remove/Update Items
392
+ ```typescript
393
+ const { data, setData } = useApi<Todo[]>('/todos', { immediate: true })
394
+
395
+ // Add item
396
+ const addTodo = (newTodo: Todo) => {
397
+ setData(prev => prev ? [...prev, newTodo] : [newTodo])
398
+ }
399
+
400
+ // Remove item
401
+ const removeTodo = (id: number) => {
402
+ setData(prev => prev?.filter(t => t.id !== id) ?? null)
403
+ }
404
+
405
+ // Update item
406
+ const updateTodo = (id: number, updates: Partial<Todo>) => {
407
+ setData(prev =>
408
+ prev?.map(t => t.id === id ? { ...t, ...updates } : t) ?? null
409
+ )
410
+ }
411
+ ```
412
+
413
+ #### Sort/Filter Locally
414
+ ```typescript
415
+ const { data, setData } = useApi<Product[]>('/products', { immediate: true })
416
+
417
+ const sortByPrice = () => {
418
+ setData(prev => prev ? [...prev].sort((a, b) => a.price - b.price) : null)
419
+ }
420
+
421
+ const filterActive = () => {
422
+ setData(prev => prev?.filter(p => p.active) ?? null)
423
+ }
424
+
425
+ // Reset to original
426
+ const resetFilters = () => execute()
427
+ ```
428
+
429
+ #### Transform in `onSuccess`
430
+
431
+ Use `setData` in `onSuccess` to transform data right after fetching. Two approaches:
432
+
433
+ **Approach 1: Same type (recommended)**
434
+ ```typescript
435
+ interface User {
436
+ id: number
437
+ firstName: string
438
+ lastName: string
439
+ fullName?: string // Optional field
440
+ }
441
+
442
+ const { data, setData } = useApi<User[]>('/users', {
443
+ immediate: true,
444
+ onSuccess: ({ data: users }) => {
445
+ // Add computed field - still User[] type
446
+ setData(users.map(u => ({
447
+ ...u,
448
+ fullName: `${u.firstName} ${u.lastName}`
449
+ })))
450
+ }
451
+ })
452
+ ```
453
+
454
+ **Approach 2: Different structure (use separate computed)**
455
+ ```typescript
456
+ interface ApiUser {
457
+ first_name: string
458
+ last_name: string
459
+ }
460
+
461
+ // If API returns different structure, use computed for transformation
462
+ const { data: rawData } = useApi<ApiUser[]>('/users', { immediate: true })
463
+
464
+ const users = computed(() =>
465
+ rawData.value?.map(u => ({
466
+ firstName: u.first_name,
467
+ lastName: u.last_name,
468
+ fullName: `${u.first_name} ${u.last_name}`
469
+ })) ?? []
470
+ )
471
+ ```
472
+
473
+ > ๐Ÿ’ก **Rule of thumb:**
474
+ > - โœ… **Use `setData` in `onSuccess`** if you're adding/modifying fields but keeping the same base type
475
+ > - โœ… **Use `computed`** if you're completely changing the data structure (e.g., snake_case โ†’ camelCase)
476
+
477
+ ---
478
+
347
479
  ## ๐Ÿ“Š Real-World Examples
348
480
 
349
481
  ### Data Table with Pagination & Sorting
@@ -389,21 +521,6 @@ const { data, loading } = useApi('/orders', {
389
521
  </template>
390
522
  ```
391
523
 
392
- ### Optimistic UI Updates
393
- ```typescript
394
- const { execute: updateProfile } = useApi('/user/profile', {
395
- method: 'PUT',
396
- onBefore: () => {
397
- // Show update immediately
398
- localProfile.value = { ...localProfile.value, ...changes }
399
- },
400
- onError: () => {
401
- // Rollback on error
402
- localProfile.value = originalProfile
403
- toast.error('Update failed')
404
- }
405
- })
406
- ```
407
524
 
408
525
  ### Request Cancellation
409
526
  ```typescript
@@ -752,11 +869,14 @@ The main composable for making HTTP requests.
752
869
  data: Ref<T | null> // Response data
753
870
  loading: Ref<boolean> // Loading state
754
871
  error: Ref<ApiError | null> // Error object
872
+ statusCode: Ref<number | null> // HTTP status code
755
873
  response: Ref<AxiosResponse<T>> // Full Axios response
756
874
 
757
875
  // Methods
758
876
  execute: (config?: AxiosRequestConfig) => Promise<T | null>
877
+ setData: (data: T | null | ((prev: T | null) => T | null)) => void
759
878
  abort: (reason?: string) => void
879
+ reset: () => void
760
880
  }
761
881
  ```
762
882
 
@@ -773,6 +893,24 @@ await execute()
773
893
  await execute({ params: { page: 2 } })
774
894
  ```
775
895
 
896
+ #### `setData(newData)`
897
+ Manually update the `data` ref. Supports direct values or updater functions:
898
+
899
+ ```typescript
900
+ const { data, setData } = useApi<User[]>('/users')
901
+
902
+ // Direct value
903
+ setData([{ id: 1, name: 'John' }])
904
+
905
+ // Updater function (like React's setState)
906
+ setData(prev => prev ? [...prev, newUser] : [newUser])
907
+
908
+ // Remove item
909
+ setData(prev => prev?.filter(u => u.id !== userId) ?? null)
910
+ ```
911
+
912
+ > **Note:** `setData` automatically clears any existing error.
913
+
776
914
  #### `abort(reason?)`
777
915
  Cancel the current request:
778
916
 
@@ -785,6 +923,20 @@ execute()
785
923
  setTimeout(() => abort('Timeout'), 5000)
786
924
  ```
787
925
 
926
+ #### `reset()`
927
+ Reset all state to initial values:
928
+
929
+ ```typescript
930
+ const { data, error, loading, reset } = useApi('/users')
931
+
932
+ // Clear everything
933
+ reset()
934
+ // data.value = null, error.value = null, loading.value = false
935
+
936
+ // Cancel after 5 seconds
937
+ setTimeout(() => abort('Timeout'), 5000)
938
+ ```
939
+
788
940
  ---
789
941
 
790
942
  ### `createApiClient(options)`
package/dist/index.cjs CHANGED
@@ -126,8 +126,13 @@ function useApiState(initialData = null, options = {}) {
126
126
  const error = (0, import_vue2.ref)(null);
127
127
  const statusCode = (0, import_vue2.ref)(null);
128
128
  const response = (0, import_vue2.ref)(null);
129
- const setData = (newData, fullResponse) => {
130
- data.value = newData;
129
+ const setData = (newDataOrUpdater, fullResponse) => {
130
+ if (typeof newDataOrUpdater === "function") {
131
+ const updater = newDataOrUpdater;
132
+ data.value = updater(data.value);
133
+ } else {
134
+ data.value = newDataOrUpdater;
135
+ }
131
136
  error.value = null;
132
137
  if (fullResponse) {
133
138
  response.value = fullResponse;
package/dist/index.d.cts CHANGED
@@ -55,6 +55,25 @@ interface UseApiReturn<T = unknown, D = unknown> {
55
55
  execute: (config?: ApiRequestConfig<D>) => Promise<T | null | undefined>;
56
56
  abort: (message?: string) => void;
57
57
  reset: () => void;
58
+ /**
59
+ * Manually update data. Supports direct value or updater function.
60
+ * Clears any existing error when called.
61
+ *
62
+ * @example
63
+ * // Direct value
64
+ * setData(newUsers)
65
+ *
66
+ * // Updater function (like React's setState)
67
+ * setData(prev => prev?.filter(u => u.active) ?? null)
68
+ *
69
+ * // Transform data after fetch
70
+ * const { data, setData } = useApi('/users', {
71
+ * onSuccess: ({ data }) => {
72
+ * setData(data.map(user => ({ ...user, fullName: `${user.first} ${user.last}` })))
73
+ * }
74
+ * })
75
+ */
76
+ setData: (newData: T | null | ((prev: T | null) => T | null)) => void;
58
77
  }
59
78
  interface ApiPluginOptions {
60
79
  axios: AxiosInstance;
@@ -151,6 +170,8 @@ declare function useApiDelete<T = unknown>(url: MaybeRefOrGetter<string | undefi
151
170
  * - !data && !error && !loading โ†’ idle
152
171
  */
153
172
 
173
+ /** Input type for setData - supports direct value or updater function */
174
+ type SetDataInput<T> = T | null | ((prev: T | null) => T | null);
154
175
  interface UseApiStateReturn<T = unknown> {
155
176
  /** Response data */
156
177
  data: Ref<T | null>;
@@ -162,8 +183,16 @@ interface UseApiStateReturn<T = unknown> {
162
183
  statusCode: Ref<number | null>;
163
184
  /** Full Axios response - includes headers, status, config, etc (optional, for advanced use cases) */
164
185
  response: Ref<AxiosResponse<T> | null>;
165
- /** Set data and clear error */
166
- setData: (newData: T | null, fullResponse?: AxiosResponse<T> | null) => void;
186
+ /**
187
+ * Set data and clear error. Supports direct value or updater function.
188
+ * @example
189
+ * // Direct value
190
+ * setData(newUsers)
191
+ *
192
+ * // Updater function (like React's setState)
193
+ * setData(prev => prev?.filter(u => u.active) ?? null)
194
+ */
195
+ setData: (newData: SetDataInput<T>, fullResponse?: AxiosResponse<T> | null) => void;
167
196
  /** Set error */
168
197
  setError: (newError: ApiError | null) => void;
169
198
  /** Set loading state */
@@ -395,4 +424,4 @@ interface AuthEventPayload {
395
424
  type AuthMonitorFn = (type: AuthEventType, payload: AuthEventPayload) => void;
396
425
  declare function setAuthMonitor(fn: AuthMonitorFn): void;
397
426
 
398
- export { type ApiError, type ApiPluginOptions, type ApiRequestConfig, type ApiState, type AuthEventPayload, AuthEventType, type AuthMode, type AuthMonitorFn, type AuthTokens$1 as AuthTokens, type UseApiOptions, type UseApiReturn, createApi, createApiClient, setAuthMonitor, setupInterceptors, tokenManager, useAbortController, useApi, useApiConfig, useApiDelete, useApiGet, useApiPatch, useApiPost, useApiPut, useApiState };
427
+ export { type ApiError, type ApiPluginOptions, type ApiRequestConfig, type ApiState, type AuthEventPayload, AuthEventType, type AuthMode, type AuthMonitorFn, type AuthTokens$1 as AuthTokens, type SetDataInput, type UseApiOptions, type UseApiReturn, createApi, createApiClient, setAuthMonitor, setupInterceptors, tokenManager, useAbortController, useApi, useApiConfig, useApiDelete, useApiGet, useApiPatch, useApiPost, useApiPut, useApiState };
package/dist/index.d.ts CHANGED
@@ -55,6 +55,25 @@ interface UseApiReturn<T = unknown, D = unknown> {
55
55
  execute: (config?: ApiRequestConfig<D>) => Promise<T | null | undefined>;
56
56
  abort: (message?: string) => void;
57
57
  reset: () => void;
58
+ /**
59
+ * Manually update data. Supports direct value or updater function.
60
+ * Clears any existing error when called.
61
+ *
62
+ * @example
63
+ * // Direct value
64
+ * setData(newUsers)
65
+ *
66
+ * // Updater function (like React's setState)
67
+ * setData(prev => prev?.filter(u => u.active) ?? null)
68
+ *
69
+ * // Transform data after fetch
70
+ * const { data, setData } = useApi('/users', {
71
+ * onSuccess: ({ data }) => {
72
+ * setData(data.map(user => ({ ...user, fullName: `${user.first} ${user.last}` })))
73
+ * }
74
+ * })
75
+ */
76
+ setData: (newData: T | null | ((prev: T | null) => T | null)) => void;
58
77
  }
59
78
  interface ApiPluginOptions {
60
79
  axios: AxiosInstance;
@@ -151,6 +170,8 @@ declare function useApiDelete<T = unknown>(url: MaybeRefOrGetter<string | undefi
151
170
  * - !data && !error && !loading โ†’ idle
152
171
  */
153
172
 
173
+ /** Input type for setData - supports direct value or updater function */
174
+ type SetDataInput<T> = T | null | ((prev: T | null) => T | null);
154
175
  interface UseApiStateReturn<T = unknown> {
155
176
  /** Response data */
156
177
  data: Ref<T | null>;
@@ -162,8 +183,16 @@ interface UseApiStateReturn<T = unknown> {
162
183
  statusCode: Ref<number | null>;
163
184
  /** Full Axios response - includes headers, status, config, etc (optional, for advanced use cases) */
164
185
  response: Ref<AxiosResponse<T> | null>;
165
- /** Set data and clear error */
166
- setData: (newData: T | null, fullResponse?: AxiosResponse<T> | null) => void;
186
+ /**
187
+ * Set data and clear error. Supports direct value or updater function.
188
+ * @example
189
+ * // Direct value
190
+ * setData(newUsers)
191
+ *
192
+ * // Updater function (like React's setState)
193
+ * setData(prev => prev?.filter(u => u.active) ?? null)
194
+ */
195
+ setData: (newData: SetDataInput<T>, fullResponse?: AxiosResponse<T> | null) => void;
167
196
  /** Set error */
168
197
  setError: (newError: ApiError | null) => void;
169
198
  /** Set loading state */
@@ -395,4 +424,4 @@ interface AuthEventPayload {
395
424
  type AuthMonitorFn = (type: AuthEventType, payload: AuthEventPayload) => void;
396
425
  declare function setAuthMonitor(fn: AuthMonitorFn): void;
397
426
 
398
- export { type ApiError, type ApiPluginOptions, type ApiRequestConfig, type ApiState, type AuthEventPayload, AuthEventType, type AuthMode, type AuthMonitorFn, type AuthTokens$1 as AuthTokens, type UseApiOptions, type UseApiReturn, createApi, createApiClient, setAuthMonitor, setupInterceptors, tokenManager, useAbortController, useApi, useApiConfig, useApiDelete, useApiGet, useApiPatch, useApiPost, useApiPut, useApiState };
427
+ export { type ApiError, type ApiPluginOptions, type ApiRequestConfig, type ApiState, type AuthEventPayload, AuthEventType, type AuthMode, type AuthMonitorFn, type AuthTokens$1 as AuthTokens, type SetDataInput, type UseApiOptions, type UseApiReturn, createApi, createApiClient, setAuthMonitor, setupInterceptors, tokenManager, useAbortController, useApi, useApiConfig, useApiDelete, useApiGet, useApiPatch, useApiPost, useApiPut, useApiState };
package/dist/index.mjs CHANGED
@@ -76,8 +76,13 @@ function useApiState(initialData = null, options = {}) {
76
76
  const error = ref(null);
77
77
  const statusCode = ref(null);
78
78
  const response = ref(null);
79
- const setData = (newData, fullResponse) => {
80
- data.value = newData;
79
+ const setData = (newDataOrUpdater, fullResponse) => {
80
+ if (typeof newDataOrUpdater === "function") {
81
+ const updater = newDataOrUpdater;
82
+ data.value = updater(data.value);
83
+ } else {
84
+ data.value = newDataOrUpdater;
85
+ }
81
86
  error.value = null;
82
87
  if (fullResponse) {
83
88
  response.value = fullResponse;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ametie/vue-muza-use",
3
- "version": "0.4.10",
3
+ "version": "0.5.0",
4
4
  "description": "Powerful Vue 3 API composable (Muza Kit) with Axios, Auto-Refresh & TypeScript",
5
5
  "author": "MortyQ",
6
6
  "license": "MIT",