@ametie/vue-muza-use 0.9.0 โ†’ 0.9.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.
Files changed (2) hide show
  1. package/README.md +226 -0
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -22,6 +22,7 @@ A production-ready composable that eliminates boilerplate and solves the hard pr
22
22
  - ๐Ÿš€ **Batch Requests** โ€” Execute multiple requests in parallel with progress tracking
23
23
  - ๐Ÿงน **Zero Memory Leaks** โ€” Automatic cleanup of pending requests on component unmount
24
24
  - ๐Ÿ”• **ignoreUpdates** โ€” Atomic updates without triggering intermediate requests
25
+ - ๐Ÿ—„๏ธ **Response Caching** โ€” In-memory cache with configurable TTL and manual invalidation
25
26
 
26
27
  **Advanced Features** (When you need them):
27
28
  - โ™ป๏ธ **Intelligent Retries** โ€” Lifecycle-aware retry logic with configurable status codes
@@ -40,6 +41,7 @@ A production-ready composable that eliminates boilerplate and solves the hard pr
40
41
  **Core Features:**
41
42
  - [Watch & Auto-Refetch](#watch--auto-refetch)
42
43
  - [ignoreUpdates โ€” Atomic Updates Without Refetch](#ignoreupdates--atomic-updates-without-refetch)
44
+ - [Response Caching](#response-caching)
43
45
  - [Polling (Background Updates)](#polling-background-updates)
44
46
  - [Error Handling](#error-handling)
45
47
  - [retry โ€” Automatic Request Retry](#retry--automatic-request-retry)
@@ -499,6 +501,184 @@ ignoreUpdates(() => {
499
501
 
500
502
  ---
501
503
 
504
+ ### Response Caching
505
+
506
+ **TL;DR: Pass `cache: 'key'` to serve repeated requests from memory instead of the network. Entries expire after 5 minutes by default.**
507
+
508
+ The cache is an in-memory `Map` shared across all `useApi` instances in the app.
509
+ It is intentionally simple: no reactive subscriptions, no persistence, no background timers.
510
+ Entries expire **lazily** โ€” stale entries are removed the next time they are read.
511
+
512
+ #### Basic Usage โ€” String Shorthand
513
+
514
+ ```vue
515
+ <script setup lang="ts">
516
+ import { useApi } from '@ametie/vue-muza-use'
517
+
518
+ const { data, loading } = useApi<Category[]>('/categories', {
519
+ cache: 'categories', // uses DEFAULT_STALE_TIME (5 minutes)
520
+ immediate: true,
521
+ })
522
+ </script>
523
+ ```
524
+
525
+ The first call hits the network and caches the result under the key `'categories'`.
526
+ Every subsequent `execute()` within 5 minutes is served from cache instantly โ€” `loading` never becomes `true` and no axios request is made.
527
+
528
+ #### Custom TTL โ€” CacheOptions Object
529
+
530
+ ```vue
531
+ <script setup lang="ts">
532
+ import { useApi } from '@ametie/vue-muza-use'
533
+
534
+ const { data, execute } = useApi<Product[]>('/products', {
535
+ cache: {
536
+ id: 'products',
537
+ staleTime: 60_000, // 1 minute
538
+ },
539
+ immediate: true,
540
+ })
541
+ </script>
542
+ ```
543
+
544
+ #### Cache Hit Behavior
545
+
546
+ When a valid cache entry is found:
547
+
548
+ | Property / Hook | Cache Hit |
549
+ |---|---|
550
+ | `loading` | stays `false` โ€” never set to `true` |
551
+ | `data` | updated immediately via `mutate()` |
552
+ | `onBefore` | **not called** |
553
+ | `onSuccess` | **not called** |
554
+ | `onFinish` | **not called** |
555
+ | axios request | **not made** |
556
+
557
+ This is intentional โ€” a cache hit is silent. If you need to know when data comes from cache vs the network, track it with `onSuccess` (only fires on network hits).
558
+
559
+ #### invalidateCache โ€” Bust Related Caches on Mutation
560
+
561
+ Use `invalidateCache` on a POST/PUT/DELETE to automatically clear caches when the mutation succeeds.
562
+
563
+ ```vue
564
+ <script setup lang="ts">
565
+ import { useApi } from '@ametie/vue-muza-use'
566
+
567
+ // GET โ€” caches the list
568
+ const { data: products, execute: reload } = useApi<Product[]>('/products', {
569
+ cache: 'products',
570
+ immediate: true,
571
+ })
572
+
573
+ // POST โ€” busts the list cache on success so the next GET hits the network
574
+ const { execute: createProduct, loading } = useApi('/products', {
575
+ method: 'POST',
576
+ invalidateCache: 'products',
577
+ })
578
+
579
+ async function submit(form: NewProduct) {
580
+ await createProduct({ data: form })
581
+ await reload() // cache is gone โ€” fetches fresh data
582
+ }
583
+ </script>
584
+ ```
585
+
586
+ `invalidateCache` fires **only on HTTP 2xx success**. It never runs in `catch` or `finally`.
587
+ Pass an array to bust multiple keys at once:
588
+
589
+ ```typescript
590
+ const { execute } = useApi('/orders', {
591
+ method: 'POST',
592
+ invalidateCache: ['orders', 'products', 'inventory'],
593
+ })
594
+ ```
595
+
596
+ #### Imperative Cache Control
597
+
598
+ Import `invalidateCache` or `clearAllCache` anywhere in your app โ€” outside components, in Pinia stores, in route guards:
599
+
600
+ ```typescript
601
+ import { invalidateCache, clearAllCache } from '@ametie/vue-muza-use'
602
+
603
+ // Bust a single key (e.g. after a WebSocket push)
604
+ invalidateCache('products')
605
+
606
+ // Bust multiple keys at once
607
+ invalidateCache(['products', 'categories'])
608
+
609
+ // Wipe everything โ€” call on logout to prevent data leaks between users
610
+ clearAllCache()
611
+ ```
612
+
613
+ #### cache + watch
614
+
615
+ When `watch` is configured, each watch-triggered `execute()` still checks the cache first:
616
+
617
+ ```vue
618
+ <script setup lang="ts">
619
+ import { useApi } from '@ametie/vue-muza-use'
620
+ import { ref } from 'vue'
621
+
622
+ const categoryId = ref<number>(1)
623
+
624
+ const { data } = useApi<Product[]>(() => `/categories/${categoryId.value}/products`, {
625
+ cache: { id: `products-cat-${categoryId.value}`, staleTime: 30_000 },
626
+ watch: categoryId,
627
+ immediate: true,
628
+ })
629
+ </script>
630
+ ```
631
+
632
+ > [!NOTE]
633
+ > The cache `id` is evaluated once when `useApi` is called. To cache per category,
634
+ > use a computed or a dynamic key string derived from your reactive state.
635
+
636
+ #### cache + retry
637
+
638
+ Cache is written **after the final successful attempt**, not after the first.
639
+ If the first attempt fails and a retry succeeds, the retry's response is cached:
640
+
641
+ ```typescript
642
+ const { data } = useApi('/reports', {
643
+ cache: 'reports',
644
+ retry: 2,
645
+ retryStatusCodes: [500, 503],
646
+ immediate: true,
647
+ })
648
+ ```
649
+
650
+ #### Complete Options Reference
651
+
652
+ | Option | Type | Default | Description |
653
+ |--------|------|---------|-------------|
654
+ | `cache` | `string \| CacheOptions` | `undefined` | Enable caching. String = `{ id, staleTime: 300_000 }` shorthand |
655
+ | `invalidateCache` | `string \| string[]` | `undefined` | Cache key(s) to delete on 2xx success |
656
+
657
+ **`CacheOptions`**
658
+
659
+ | Field | Type | Default | Description |
660
+ |-------|------|---------|-------------|
661
+ | `id` | `string` | โ€” | Unique cache key |
662
+ | `staleTime` | `number` | `300_000` | TTL in milliseconds. Entry is deleted on next read after this time |
663
+
664
+ #### Out of Scope (by design)
665
+
666
+ The following are intentionally **not** supported in v1:
667
+
668
+ - ๐Ÿšซ No reactive cache entries โ€” the cache is a plain `Map`, not Vue refs
669
+ - ๐Ÿšซ No `localStorage` / `sessionStorage` persistence
670
+ - ๐Ÿšซ No background TTL timers โ€” expiry is checked lazily on read
671
+ - ๐Ÿšซ No cache for `useApiBatch` โ€” batch requests manage their own state
672
+ - ๐Ÿšซ No automatic refetch on cache invalidation โ€” call `execute()` manually after invalidating
673
+ - ๐Ÿšซ No request deduplication โ€” concurrent calls for the same key each fire their own request
674
+
675
+ > [!WARNING]
676
+ > The cache store is **module-level** (a singleton). In SSR / Node.js environments it is
677
+ > shared between all incoming requests. Call `clearAllCache()` between requests or avoid
678
+ > using caching in SSR contexts.
679
+
680
+ ---
681
+
502
682
  ### Polling (Background Updates)
503
683
 
504
684
  **TL;DR: Keep data fresh with smart polling that automatically pauses when the browser tab is hidden.**
@@ -1511,6 +1691,13 @@ function useMyCustomComposable<T>(fetchFn: () => Promise<T>) {
1511
1691
  | `watch` | `WatchSource \| WatchSource[]` | `undefined` | One or more refs to watch โ€” request re-fires when any of them change |
1512
1692
  | `debounce` | `number` | `0` | Milliseconds to wait after the last watch change before firing the request |
1513
1693
 
1694
+ **Caching:**
1695
+
1696
+ | Option | Type | Default | Description |
1697
+ |--------|------|---------|-------------|
1698
+ | `cache` | `string \| CacheOptions` | `undefined` | Cache the response in memory. String shorthand uses default 5-min TTL. See [Response Caching](#response-caching) |
1699
+ | `invalidateCache` | `string \| string[]` | `undefined` | Cache key(s) to delete on 2xx success. Never fires on error |
1700
+
1514
1701
  **Polling:**
1515
1702
 
1516
1703
  | Option | Type | Default | Description |
@@ -1768,6 +1955,45 @@ const { data, loading, error, mutate, setLoading, setError, reset } =
1768
1955
 
1769
1956
  ---
1770
1957
 
1958
+ ### `invalidateCache(id)` / `clearAllCache()`
1959
+
1960
+ **TL;DR: Imperatively delete one, many, or all cache entries from anywhere in your app.**
1961
+
1962
+ ```typescript
1963
+ import { invalidateCache, clearAllCache } from '@ametie/vue-muza-use'
1964
+ ```
1965
+
1966
+ | Function | Signature | Description |
1967
+ |----------|-----------|-------------|
1968
+ | `invalidateCache` | `(id: string \| string[]) => void` | Delete one or more cache entries by key |
1969
+ | `clearAllCache` | `() => void` | Wipe the entire cache โ€” use on logout |
1970
+
1971
+ **Example โ€” bust cache after a WebSocket push:**
1972
+
1973
+ ```typescript
1974
+ // pinia store or composable outside a component
1975
+ import { invalidateCache } from '@ametie/vue-muza-use'
1976
+
1977
+ socket.on('products:updated', () => {
1978
+ invalidateCache('products')
1979
+ })
1980
+ ```
1981
+
1982
+ **Example โ€” clear all on logout:**
1983
+
1984
+ ```typescript
1985
+ import { clearAllCache } from '@ametie/vue-muza-use'
1986
+ import { tokenManager } from '@ametie/vue-muza-use'
1987
+
1988
+ function logout() {
1989
+ tokenManager.clearTokens()
1990
+ clearAllCache() // prevent stale data from leaking to the next user session
1991
+ router.push('/login')
1992
+ }
1993
+ ```
1994
+
1995
+ ---
1996
+
1771
1997
  ## ๐Ÿงฉ Common Patterns
1772
1998
 
1773
1999
  ### 1. Search with Debounce and Reset
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ametie/vue-muza-use",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Powerful Vue 3 API composable (Muza Kit) with Axios, Auto-Refresh & TypeScript",
5
5
  "author": "MortyQ",
6
6
  "license": "MIT",