@ametie/vue-muza-use 0.4.10 โ 0.6.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 +467 -17
- package/dist/index.cjs +245 -2
- package/dist/index.d.cts +166 -3
- package/dist/index.d.ts +166 -3
- package/dist/index.mjs +244 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,18 +13,50 @@ 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
|
|
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
|
+
|
|
25
|
+
**Advanced Features** (When you need them):
|
|
26
|
+
- โป๏ธ **Intelligent Retries** โ Lifecycle-aware retry logic that respects component unmounting
|
|
27
|
+
- ๐ **JWT Token Management** โ Automatic token refresh with request queueing on 401 responses
|
|
24
28
|
- ๐๏ธ **Flexible Architecture** โ Bring your own Axios instance with full configuration control
|
|
25
29
|
|
|
26
30
|
---
|
|
27
31
|
|
|
32
|
+
## ๐ Table of Contents
|
|
33
|
+
|
|
34
|
+
**Getting Started:**
|
|
35
|
+
- [Installation](#-installation)
|
|
36
|
+
- [Quick Start](#-quick-start)
|
|
37
|
+
- [Basic Usage](#-basic-usage)
|
|
38
|
+
|
|
39
|
+
**Core Features:**
|
|
40
|
+
- [Watch & Auto-Refetch](#watch--auto-refetch)
|
|
41
|
+
- [Polling](#polling-background-updates)
|
|
42
|
+
- [Error Handling](#error-handling)
|
|
43
|
+
- [Loading States](#loading-states)
|
|
44
|
+
- [Manual Data Updates](#manual-data-updates)
|
|
45
|
+
|
|
46
|
+
**Real-World Examples:**
|
|
47
|
+
- [Data Table with Pagination](#data-table-with-pagination--sorting)
|
|
48
|
+
- [Request Cancellation](#request-cancellation)
|
|
49
|
+
- [Batch Requests](#batch-requests)
|
|
50
|
+
|
|
51
|
+
**Advanced:**
|
|
52
|
+
- [Custom Axios Instance](#-advanced-configuration)
|
|
53
|
+
- [Authentication & Tokens](#-authentication--token-management) *(Optional)*
|
|
54
|
+
- [API Reference](#-api-reference)
|
|
55
|
+
|
|
56
|
+
> ๐ก **New to the library?** Start with [Quick Start](#-quick-start), then explore [Basic Usage](#-basic-usage). Skip authentication until you need it!
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
28
60
|
## ๐ฆ Installation
|
|
29
61
|
|
|
30
62
|
```bash
|
|
@@ -344,6 +376,108 @@ const { execute } = useApi('/analytics', {
|
|
|
344
376
|
|
|
345
377
|
---
|
|
346
378
|
|
|
379
|
+
### Manual Data Updates
|
|
380
|
+
|
|
381
|
+
Use `setData` to manually update the data ref. Supports direct values or updater functions (like React's `setState`).
|
|
382
|
+
|
|
383
|
+
> ๐ **When to use `setData`:**
|
|
384
|
+
> โ
Adding/removing/updating items in arrays
|
|
385
|
+
> โ
Local sorting/filtering (without refetching)
|
|
386
|
+
> โ
Transform data in `onSuccess` (adding computed fields)
|
|
387
|
+
>
|
|
388
|
+
> **When to use `computed` instead:**
|
|
389
|
+
> โ
Completely changing data structure (e.g., API format โ App format)
|
|
390
|
+
> โ
Extracting nested data that changes the return type
|
|
391
|
+
> โ
Complex transformations that depend on other refs
|
|
392
|
+
|
|
393
|
+
#### Add/Remove/Update Items
|
|
394
|
+
```typescript
|
|
395
|
+
const { data, setData } = useApi<Todo[]>('/todos', { immediate: true })
|
|
396
|
+
|
|
397
|
+
// Add item
|
|
398
|
+
const addTodo = (newTodo: Todo) => {
|
|
399
|
+
setData(prev => prev ? [...prev, newTodo] : [newTodo])
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Remove item
|
|
403
|
+
const removeTodo = (id: number) => {
|
|
404
|
+
setData(prev => prev?.filter(t => t.id !== id) ?? null)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Update item
|
|
408
|
+
const updateTodo = (id: number, updates: Partial<Todo>) => {
|
|
409
|
+
setData(prev =>
|
|
410
|
+
prev?.map(t => t.id === id ? { ...t, ...updates } : t) ?? null
|
|
411
|
+
)
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
#### Sort/Filter Locally
|
|
416
|
+
```typescript
|
|
417
|
+
const { data, setData } = useApi<Product[]>('/products', { immediate: true })
|
|
418
|
+
|
|
419
|
+
const sortByPrice = () => {
|
|
420
|
+
setData(prev => prev ? [...prev].sort((a, b) => a.price - b.price) : null)
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const filterActive = () => {
|
|
424
|
+
setData(prev => prev?.filter(p => p.active) ?? null)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Reset to original
|
|
428
|
+
const resetFilters = () => execute()
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
#### Transform in `onSuccess`
|
|
432
|
+
|
|
433
|
+
Use `setData` in `onSuccess` to transform data right after fetching. Two approaches:
|
|
434
|
+
|
|
435
|
+
**Approach 1: Same type (recommended)**
|
|
436
|
+
```typescript
|
|
437
|
+
interface User {
|
|
438
|
+
id: number
|
|
439
|
+
firstName: string
|
|
440
|
+
lastName: string
|
|
441
|
+
fullName?: string // Optional field
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const { data, setData } = useApi<User[]>('/users', {
|
|
445
|
+
immediate: true,
|
|
446
|
+
onSuccess: ({ data: users }) => {
|
|
447
|
+
// Add computed field - still User[] type
|
|
448
|
+
setData(users.map(u => ({
|
|
449
|
+
...u,
|
|
450
|
+
fullName: `${u.firstName} ${u.lastName}`
|
|
451
|
+
})))
|
|
452
|
+
}
|
|
453
|
+
})
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**Approach 2: Different structure (use separate computed)**
|
|
457
|
+
```typescript
|
|
458
|
+
interface ApiUser {
|
|
459
|
+
first_name: string
|
|
460
|
+
last_name: string
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// If API returns different structure, use computed for transformation
|
|
464
|
+
const { data: rawData } = useApi<ApiUser[]>('/users', { immediate: true })
|
|
465
|
+
|
|
466
|
+
const users = computed(() =>
|
|
467
|
+
rawData.value?.map(u => ({
|
|
468
|
+
firstName: u.first_name,
|
|
469
|
+
lastName: u.last_name,
|
|
470
|
+
fullName: `${u.first_name} ${u.last_name}`
|
|
471
|
+
})) ?? []
|
|
472
|
+
)
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
> ๐ก **Rule of thumb:**
|
|
476
|
+
> - โ
**Use `setData` in `onSuccess`** if you're adding/modifying fields but keeping the same base type
|
|
477
|
+
> - โ
**Use `computed`** if you're completely changing the data structure (e.g., snake_case โ camelCase)
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
347
481
|
## ๐ Real-World Examples
|
|
348
482
|
|
|
349
483
|
### Data Table with Pagination & Sorting
|
|
@@ -389,21 +523,6 @@ const { data, loading } = useApi('/orders', {
|
|
|
389
523
|
</template>
|
|
390
524
|
```
|
|
391
525
|
|
|
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
526
|
|
|
408
527
|
### Request Cancellation
|
|
409
528
|
```typescript
|
|
@@ -424,6 +543,219 @@ const resetFilters = () => {
|
|
|
424
543
|
|
|
425
544
|
---
|
|
426
545
|
|
|
546
|
+
### Batch Requests
|
|
547
|
+
|
|
548
|
+
Execute multiple API requests in parallel with full reactive state, progress tracking, and error tolerance.
|
|
549
|
+
|
|
550
|
+
#### Basic Usage
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
import { useApiBatch } from '@ametie/vue-muza-use'
|
|
554
|
+
|
|
555
|
+
interface User {
|
|
556
|
+
id: number
|
|
557
|
+
name: string
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const {
|
|
561
|
+
successfulData, // Ref<User[]> - only successful results
|
|
562
|
+
loading, // Ref<boolean>
|
|
563
|
+
progress, // Ref<{ completed, total, percentage, succeeded, failed }>
|
|
564
|
+
execute
|
|
565
|
+
} = useApiBatch<User>([
|
|
566
|
+
'/users/1',
|
|
567
|
+
'/users/2',
|
|
568
|
+
'/users/3'
|
|
569
|
+
])
|
|
570
|
+
|
|
571
|
+
await execute()
|
|
572
|
+
console.log(successfulData.value) // [User, User, User]
|
|
573
|
+
console.log(progress.value) // { completed: 3, total: 3, percentage: 100, succeeded: 3, failed: 0 }
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
#### Error Tolerance (Default)
|
|
577
|
+
|
|
578
|
+
By default, `useApiBatch` uses `settled: true` โ failed requests don't stop the batch:
|
|
579
|
+
|
|
580
|
+
```typescript
|
|
581
|
+
const {
|
|
582
|
+
successfulData,
|
|
583
|
+
errors, // Ref<ApiError[]> - all errors
|
|
584
|
+
progress,
|
|
585
|
+
execute
|
|
586
|
+
} = useApiBatch<User>([
|
|
587
|
+
'/users/1',
|
|
588
|
+
'/users/999', // Will fail (404)
|
|
589
|
+
'/users/3'
|
|
590
|
+
])
|
|
591
|
+
|
|
592
|
+
await execute()
|
|
593
|
+
|
|
594
|
+
console.log(successfulData.value.length) // 2 (successful)
|
|
595
|
+
console.log(errors.value.length) // 1 (failed)
|
|
596
|
+
console.log(progress.value) // { succeeded: 2, failed: 1, ... }
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
#### Strict Mode
|
|
600
|
+
|
|
601
|
+
Fail immediately on first error:
|
|
602
|
+
|
|
603
|
+
```typescript
|
|
604
|
+
const { execute } = useApiBatch<User>(urls, {
|
|
605
|
+
settled: false // First error will reject the entire batch
|
|
606
|
+
})
|
|
607
|
+
|
|
608
|
+
try {
|
|
609
|
+
await execute()
|
|
610
|
+
} catch (error) {
|
|
611
|
+
console.log('Batch failed:', error.message)
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
#### With Progress Tracking
|
|
616
|
+
|
|
617
|
+
Perfect for loading indicators and progress bars:
|
|
618
|
+
|
|
619
|
+
```vue
|
|
620
|
+
<script setup lang="ts">
|
|
621
|
+
const { loading, progress, execute } = useApiBatch<User>(urls, {
|
|
622
|
+
onProgress: (p) => {
|
|
623
|
+
console.log(`${p.percentage}% complete (${p.succeeded} ok, ${p.failed} failed)`)
|
|
624
|
+
}
|
|
625
|
+
})
|
|
626
|
+
</script>
|
|
627
|
+
|
|
628
|
+
<template>
|
|
629
|
+
<div v-if="loading">
|
|
630
|
+
<div class="progress-bar">
|
|
631
|
+
<div :style="{ width: progress.percentage + '%' }"></div>
|
|
632
|
+
</div>
|
|
633
|
+
<span>{{ progress.completed }} / {{ progress.total }}</span>
|
|
634
|
+
</div>
|
|
635
|
+
</template>
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
#### Concurrency Limit
|
|
639
|
+
|
|
640
|
+
Control how many requests run in parallel (useful for rate limiting):
|
|
641
|
+
|
|
642
|
+
```typescript
|
|
643
|
+
// Only 3 requests at a time
|
|
644
|
+
const { execute } = useApiBatch<User>(hundredUrls, {
|
|
645
|
+
concurrency: 3
|
|
646
|
+
})
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
#### Reactive URLs
|
|
650
|
+
|
|
651
|
+
URLs can be reactive โ use refs or computed:
|
|
652
|
+
|
|
653
|
+
```typescript
|
|
654
|
+
const userIds = ref([1, 2, 3])
|
|
655
|
+
const urls = computed(() => userIds.value.map(id => `/users/${id}`))
|
|
656
|
+
|
|
657
|
+
const { successfulData, execute } = useApiBatch<User>(urls, {
|
|
658
|
+
immediate: true // Execute on mount
|
|
659
|
+
})
|
|
660
|
+
|
|
661
|
+
// When userIds changes, call execute() to refetch
|
|
662
|
+
watch(userIds, () => execute())
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
#### Auto Re-Execute with Watch
|
|
666
|
+
|
|
667
|
+
```typescript
|
|
668
|
+
const filters = ref({ status: 'active' })
|
|
669
|
+
|
|
670
|
+
const { data } = useApiBatch<User>(urls, {
|
|
671
|
+
watch: filters, // Re-execute when filters change
|
|
672
|
+
immediate: true
|
|
673
|
+
})
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
#### Item-Level Callbacks
|
|
677
|
+
|
|
678
|
+
```typescript
|
|
679
|
+
const { execute } = useApiBatch<User>(urls, {
|
|
680
|
+
onItemSuccess: (item, index) => {
|
|
681
|
+
console.log(`โ
[${index}] Loaded: ${item.url}`)
|
|
682
|
+
},
|
|
683
|
+
onItemError: (item, index) => {
|
|
684
|
+
console.log(`โ [${index}] Failed: ${item.url}`, item.error?.message)
|
|
685
|
+
},
|
|
686
|
+
onFinish: (results) => {
|
|
687
|
+
console.log(`Batch complete: ${results.length} items processed`)
|
|
688
|
+
}
|
|
689
|
+
})
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
#### Full Return Type
|
|
693
|
+
|
|
694
|
+
```typescript
|
|
695
|
+
const {
|
|
696
|
+
data, // Ref<BatchResultItem<T>[]> - all results with metadata
|
|
697
|
+
successfulData, // Ref<T[]> - only successful data (computed)
|
|
698
|
+
loading, // Ref<boolean>
|
|
699
|
+
error, // Ref<ApiError | null> - set if ALL requests failed
|
|
700
|
+
errors, // Ref<ApiError[]> - all individual errors
|
|
701
|
+
progress, // Ref<BatchProgress>
|
|
702
|
+
execute, // () => Promise<BatchResultItem<T>[]>
|
|
703
|
+
abort, // (message?: string) => void
|
|
704
|
+
reset // () => void
|
|
705
|
+
} = useApiBatch<User>(urls)
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
#### BatchResultItem Structure
|
|
709
|
+
|
|
710
|
+
Each item in `data` contains:
|
|
711
|
+
|
|
712
|
+
```typescript
|
|
713
|
+
interface BatchResultItem<T> {
|
|
714
|
+
url: string // The requested URL
|
|
715
|
+
index: number // Position in original array
|
|
716
|
+
success: boolean // Whether request succeeded
|
|
717
|
+
data: T | null // Response data (null if failed)
|
|
718
|
+
error: ApiError | null // Error details (null if succeeded)
|
|
719
|
+
statusCode: number | null
|
|
720
|
+
}
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
#### Real-World Example: Dashboard Loader
|
|
724
|
+
|
|
725
|
+
```vue
|
|
726
|
+
<script setup lang="ts">
|
|
727
|
+
const dashboardUrls = [
|
|
728
|
+
'/api/stats',
|
|
729
|
+
'/api/recent-orders',
|
|
730
|
+
'/api/notifications',
|
|
731
|
+
'/api/user-activity'
|
|
732
|
+
]
|
|
733
|
+
|
|
734
|
+
const {
|
|
735
|
+
data: results,
|
|
736
|
+
loading,
|
|
737
|
+
progress,
|
|
738
|
+
execute
|
|
739
|
+
} = useApiBatch(dashboardUrls, {
|
|
740
|
+
immediate: true,
|
|
741
|
+
onProgress: (p) => console.log(`Dashboard loading: ${p.percentage}%`)
|
|
742
|
+
})
|
|
743
|
+
|
|
744
|
+
// Extract individual data
|
|
745
|
+
const stats = computed(() => results.value.find(r => r.url.includes('stats'))?.data)
|
|
746
|
+
const orders = computed(() => results.value.find(r => r.url.includes('orders'))?.data)
|
|
747
|
+
</script>
|
|
748
|
+
|
|
749
|
+
<template>
|
|
750
|
+
<div v-if="loading" class="loading">
|
|
751
|
+
Loading dashboard... {{ progress.percentage }}%
|
|
752
|
+
</div>
|
|
753
|
+
<Dashboard v-else :stats="stats" :orders="orders" />
|
|
754
|
+
</template>
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
---
|
|
758
|
+
|
|
427
759
|
## โ๏ธ Advanced Configuration
|
|
428
760
|
|
|
429
761
|
### Custom Axios Instance
|
|
@@ -752,11 +1084,14 @@ The main composable for making HTTP requests.
|
|
|
752
1084
|
data: Ref<T | null> // Response data
|
|
753
1085
|
loading: Ref<boolean> // Loading state
|
|
754
1086
|
error: Ref<ApiError | null> // Error object
|
|
1087
|
+
statusCode: Ref<number | null> // HTTP status code
|
|
755
1088
|
response: Ref<AxiosResponse<T>> // Full Axios response
|
|
756
1089
|
|
|
757
1090
|
// Methods
|
|
758
1091
|
execute: (config?: AxiosRequestConfig) => Promise<T | null>
|
|
1092
|
+
setData: (data: T | null | ((prev: T | null) => T | null)) => void
|
|
759
1093
|
abort: (reason?: string) => void
|
|
1094
|
+
reset: () => void
|
|
760
1095
|
}
|
|
761
1096
|
```
|
|
762
1097
|
|
|
@@ -773,6 +1108,24 @@ await execute()
|
|
|
773
1108
|
await execute({ params: { page: 2 } })
|
|
774
1109
|
```
|
|
775
1110
|
|
|
1111
|
+
#### `setData(newData)`
|
|
1112
|
+
Manually update the `data` ref. Supports direct values or updater functions:
|
|
1113
|
+
|
|
1114
|
+
```typescript
|
|
1115
|
+
const { data, setData } = useApi<User[]>('/users')
|
|
1116
|
+
|
|
1117
|
+
// Direct value
|
|
1118
|
+
setData([{ id: 1, name: 'John' }])
|
|
1119
|
+
|
|
1120
|
+
// Updater function (like React's setState)
|
|
1121
|
+
setData(prev => prev ? [...prev, newUser] : [newUser])
|
|
1122
|
+
|
|
1123
|
+
// Remove item
|
|
1124
|
+
setData(prev => prev?.filter(u => u.id !== userId) ?? null)
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
> **Note:** `setData` automatically clears any existing error.
|
|
1128
|
+
|
|
776
1129
|
#### `abort(reason?)`
|
|
777
1130
|
Cancel the current request:
|
|
778
1131
|
|
|
@@ -785,6 +1138,20 @@ execute()
|
|
|
785
1138
|
setTimeout(() => abort('Timeout'), 5000)
|
|
786
1139
|
```
|
|
787
1140
|
|
|
1141
|
+
#### `reset()`
|
|
1142
|
+
Reset all state to initial values:
|
|
1143
|
+
|
|
1144
|
+
```typescript
|
|
1145
|
+
const { data, error, loading, reset } = useApi('/users')
|
|
1146
|
+
|
|
1147
|
+
// Clear everything
|
|
1148
|
+
reset()
|
|
1149
|
+
// data.value = null, error.value = null, loading.value = false
|
|
1150
|
+
|
|
1151
|
+
// Cancel after 5 seconds
|
|
1152
|
+
setTimeout(() => abort('Timeout'), 5000)
|
|
1153
|
+
```
|
|
1154
|
+
|
|
788
1155
|
---
|
|
789
1156
|
|
|
790
1157
|
### `createApiClient(options)`
|
|
@@ -899,6 +1266,89 @@ app.use(createApi({
|
|
|
899
1266
|
|
|
900
1267
|
---
|
|
901
1268
|
|
|
1269
|
+
### `useApiBatch<T>(urls, options)`
|
|
1270
|
+
|
|
1271
|
+
Execute multiple API requests in parallel with full reactive state.
|
|
1272
|
+
|
|
1273
|
+
**Type Parameters:**
|
|
1274
|
+
- `T` โ Response data type for each request
|
|
1275
|
+
|
|
1276
|
+
**Arguments:**
|
|
1277
|
+
|
|
1278
|
+
| Argument | Type | Description |
|
|
1279
|
+
|----------|------|-------------|
|
|
1280
|
+
| `urls` | `MaybeRefOrGetter<string[]>` | Array of API endpoints. Can be static array, ref, or getter. |
|
|
1281
|
+
| `options` | `UseApiBatchOptions<T>` | Configuration object (see below). |
|
|
1282
|
+
|
|
1283
|
+
---
|
|
1284
|
+
|
|
1285
|
+
#### Batch Options
|
|
1286
|
+
|
|
1287
|
+
| Option | Type | Default | Description |
|
|
1288
|
+
|--------|------|---------|-------------|
|
|
1289
|
+
| `settled` | `boolean` | `true` | If `true`, failed requests don't stop the batch. If `false`, first error rejects entire batch. |
|
|
1290
|
+
| `concurrency` | `number` | `undefined` | Max parallel requests. Default: unlimited. |
|
|
1291
|
+
| `immediate` | `boolean` | `false` | Auto-execute on mount. |
|
|
1292
|
+
| `skipErrorNotification` | `boolean` | `true` | Skip global error handler for individual failures. |
|
|
1293
|
+
| `watch` | `WatchSource \| WatchSource[]` | `undefined` | Re-execute when sources change. |
|
|
1294
|
+
|
|
1295
|
+
**Callbacks:**
|
|
1296
|
+
|
|
1297
|
+
| Option | Type | Description |
|
|
1298
|
+
|--------|------|-------------|
|
|
1299
|
+
| `onItemSuccess` | `(item: BatchResultItem<T>, index: number) => void` | Called when individual request succeeds. |
|
|
1300
|
+
| `onItemError` | `(item: BatchResultItem<T>, index: number) => void` | Called when individual request fails. |
|
|
1301
|
+
| `onProgress` | `(progress: BatchProgress) => void` | Called when progress updates. |
|
|
1302
|
+
| `onFinish` | `(results: BatchResultItem<T>[]) => void` | Called when all requests complete. |
|
|
1303
|
+
|
|
1304
|
+
---
|
|
1305
|
+
|
|
1306
|
+
#### Batch Return Values
|
|
1307
|
+
|
|
1308
|
+
```typescript
|
|
1309
|
+
{
|
|
1310
|
+
// State
|
|
1311
|
+
data: Ref<BatchResultItem<T>[]> // All results with metadata
|
|
1312
|
+
successfulData: Ref<T[]> // Only successful data (computed)
|
|
1313
|
+
loading: Ref<boolean> // True while any request pending
|
|
1314
|
+
error: Ref<ApiError | null> // Set if ALL requests failed
|
|
1315
|
+
errors: Ref<ApiError[]> // All individual errors
|
|
1316
|
+
progress: Ref<BatchProgress> // Progress tracking
|
|
1317
|
+
|
|
1318
|
+
// Methods
|
|
1319
|
+
execute: () => Promise<BatchResultItem<T>[]>
|
|
1320
|
+
abort: (message?: string) => void
|
|
1321
|
+
reset: () => void
|
|
1322
|
+
}
|
|
1323
|
+
```
|
|
1324
|
+
|
|
1325
|
+
#### `BatchProgress`
|
|
1326
|
+
|
|
1327
|
+
```typescript
|
|
1328
|
+
interface BatchProgress {
|
|
1329
|
+
completed: number // Requests finished (success + failed)
|
|
1330
|
+
total: number // Total requests
|
|
1331
|
+
percentage: number // 0-100
|
|
1332
|
+
succeeded: number // Successful requests
|
|
1333
|
+
failed: number // Failed requests
|
|
1334
|
+
}
|
|
1335
|
+
```
|
|
1336
|
+
|
|
1337
|
+
#### `BatchResultItem<T>`
|
|
1338
|
+
|
|
1339
|
+
```typescript
|
|
1340
|
+
interface BatchResultItem<T> {
|
|
1341
|
+
url: string // Requested URL
|
|
1342
|
+
index: number // Position in original array
|
|
1343
|
+
success: boolean // Whether succeeded
|
|
1344
|
+
data: T | null // Response data
|
|
1345
|
+
error: ApiError | null // Error if failed
|
|
1346
|
+
statusCode: number | null
|
|
1347
|
+
}
|
|
1348
|
+
```
|
|
1349
|
+
|
|
1350
|
+
---
|
|
1351
|
+
|
|
902
1352
|
### `useAbortController()`
|
|
903
1353
|
|
|
904
1354
|
Access the global abort controller for cancelling multiple requests.
|