@enfyra/sdk-nuxt 0.2.1 → 0.2.2
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 +47 -6
- package/dist/composables/useEnfyraApi.mjs +29 -5
- package/dist/index.d.ts +16 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/module.json +1 -1
- package/package.json +1 -1
- package/src/composables/useEnfyraApi.ts +47 -11
- package/src/types/index.ts +18 -6
package/README.md
CHANGED
|
@@ -143,6 +143,9 @@ await execute({
|
|
|
143
143
|
- `query?: Record<string, any>` - URL query parameters
|
|
144
144
|
- `headers?: Record<string, string>` - Custom headers
|
|
145
145
|
- `errorContext?: string` - Error context for logging
|
|
146
|
+
- `onError?: (error: ApiError, context?: string) => void` - Custom error handler
|
|
147
|
+
- `batchSize?: number` - Batch size for chunking large operations (default: no limit)
|
|
148
|
+
- `concurrent?: number` - Maximum concurrent requests (default: no limit)
|
|
146
149
|
- `key?: string` - Cache key (SSR mode, optional)
|
|
147
150
|
- `default?: () => T` - Default value (SSR mode only)
|
|
148
151
|
|
|
@@ -153,8 +156,10 @@ await execute({
|
|
|
153
156
|
**Execute Options (Client mode only):**
|
|
154
157
|
- `id?: string | number` - Single resource ID
|
|
155
158
|
- `ids?: (string | number)[]` - Batch operation IDs (PATCH/DELETE)
|
|
156
|
-
- `files?: FormData[]` -
|
|
159
|
+
- `files?: FormData[]` - Array of FormData objects for batch upload (POST)
|
|
157
160
|
- `body?: any` - Override request body
|
|
161
|
+
- `batchSize?: number` - Override batch size for this execution
|
|
162
|
+
- `concurrent?: number` - Override concurrent limit for this execution
|
|
158
163
|
|
|
159
164
|
### `useEnfyraAuth()`
|
|
160
165
|
|
|
@@ -178,7 +183,7 @@ await fetchUser() // Refresh user data
|
|
|
178
183
|
### Batch Operations
|
|
179
184
|
|
|
180
185
|
```typescript
|
|
181
|
-
//
|
|
186
|
+
// Basic batch delete - unlimited parallel requests
|
|
182
187
|
const { execute: deleteItems } = useEnfyraApi('/items', {
|
|
183
188
|
method: 'delete',
|
|
184
189
|
errorContext: 'Delete Items'
|
|
@@ -186,14 +191,50 @@ const { execute: deleteItems } = useEnfyraApi('/items', {
|
|
|
186
191
|
|
|
187
192
|
await deleteItems({ ids: ['1', '2', '3'] });
|
|
188
193
|
|
|
189
|
-
//
|
|
190
|
-
const { execute:
|
|
191
|
-
method: '
|
|
194
|
+
// Advanced batch operations with concurrency control
|
|
195
|
+
const { execute: deleteMany } = useEnfyraApi('/users', {
|
|
196
|
+
method: 'delete',
|
|
197
|
+
batchSize: 10, // Process 10 items at a time
|
|
198
|
+
concurrent: 3, // Max 3 requests simultaneously
|
|
199
|
+
onError: (error, context) => toast.error(`${context}: ${error.message}`)
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Delete 100 users in controlled batches
|
|
203
|
+
await deleteMany({ ids: Array.from({length: 100}, (_, i) => `user-${i}`) });
|
|
204
|
+
|
|
205
|
+
// Override batch settings per execution
|
|
206
|
+
const { execute: updateUsers } = useEnfyraApi('/users', {
|
|
207
|
+
method: 'patch',
|
|
208
|
+
batchSize: 20, // Default: 20 per batch
|
|
209
|
+
concurrent: 5 // Default: 5 concurrent
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// This execution uses different settings
|
|
213
|
+
await updateUsers({
|
|
214
|
+
ids: largeUserList,
|
|
215
|
+
body: { status: 'active' },
|
|
216
|
+
batchSize: 50, // Override: 50 per batch for this call
|
|
217
|
+
concurrent: 10 // Override: 10 concurrent for this call
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Batch file upload with progress control
|
|
221
|
+
const { execute: uploadFiles } = useEnfyraApi('/file_definition', {
|
|
222
|
+
method: 'post',
|
|
223
|
+
batchSize: 5, // Upload 5 files at a time
|
|
224
|
+
concurrent: 2, // Max 2 uploads simultaneously
|
|
192
225
|
errorContext: 'Upload Files'
|
|
193
226
|
});
|
|
194
227
|
|
|
228
|
+
// Convert files to FormData array (matches enfyra_app pattern)
|
|
229
|
+
const formDataArray = selectedFiles.map(file => {
|
|
230
|
+
const formData = new FormData();
|
|
231
|
+
formData.append('file', file);
|
|
232
|
+
formData.append('folder', folderId || 'null');
|
|
233
|
+
return formData;
|
|
234
|
+
});
|
|
235
|
+
|
|
195
236
|
await uploadFiles({
|
|
196
|
-
files:
|
|
237
|
+
files: formDataArray // Array of FormData objects
|
|
197
238
|
});
|
|
198
239
|
```
|
|
199
240
|
|
|
@@ -16,7 +16,7 @@ function handleError(error, context, customHandler) {
|
|
|
16
16
|
return apiError;
|
|
17
17
|
}
|
|
18
18
|
export function useEnfyraApi(path, opts = {}) {
|
|
19
|
-
const { method = "get", body, query, errorContext, onError, ssr, key } = opts;
|
|
19
|
+
const { method = "get", body, query, errorContext, onError, ssr, key, batchSize, concurrent } = opts;
|
|
20
20
|
if (ssr) {
|
|
21
21
|
const config = useRuntimeConfig().public.enfyraSDK;
|
|
22
22
|
const basePath = (typeof path === "function" ? path() : path).replace(/^\/?api\/?/, "").replace(/^\/+/, "");
|
|
@@ -65,12 +65,38 @@ export function useEnfyraApi(path, opts = {}) {
|
|
|
65
65
|
const basePath = (typeof path === "function" ? path() : path).replace(/^\/?api\/?/, "").replace(/^\/+/, "");
|
|
66
66
|
const finalBody = executeOpts?.body || unref(body);
|
|
67
67
|
const finalQuery = unref(query);
|
|
68
|
+
const effectiveBatchSize = executeOpts?.batchSize ?? batchSize;
|
|
69
|
+
const effectiveConcurrent = executeOpts?.concurrent ?? concurrent;
|
|
68
70
|
const buildPath = (...segments) => {
|
|
69
71
|
return segments.filter(Boolean).join("/");
|
|
70
72
|
};
|
|
71
73
|
const fullBaseURL = apiUrl + (apiPrefix || "");
|
|
74
|
+
async function processBatch(items, processor) {
|
|
75
|
+
const results = [];
|
|
76
|
+
if (!effectiveBatchSize && !effectiveConcurrent) {
|
|
77
|
+
const promises = items.map(processor);
|
|
78
|
+
return await Promise.all(promises);
|
|
79
|
+
}
|
|
80
|
+
const chunks = effectiveBatchSize ? Array.from(
|
|
81
|
+
{ length: Math.ceil(items.length / effectiveBatchSize) },
|
|
82
|
+
(_, i) => items.slice(i * effectiveBatchSize, i * effectiveBatchSize + effectiveBatchSize)
|
|
83
|
+
) : [items];
|
|
84
|
+
for (const chunk of chunks) {
|
|
85
|
+
if (effectiveConcurrent && chunk.length > effectiveConcurrent) {
|
|
86
|
+
for (let i = 0; i < chunk.length; i += effectiveConcurrent) {
|
|
87
|
+
const batch = chunk.slice(i, i + effectiveConcurrent);
|
|
88
|
+
const batchResults = await Promise.all(batch.map(processor));
|
|
89
|
+
results.push(...batchResults);
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
const chunkResults = await Promise.all(chunk.map(processor));
|
|
93
|
+
results.push(...chunkResults);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return results;
|
|
97
|
+
}
|
|
72
98
|
if (!opts.disableBatch && executeOpts?.ids && executeOpts.ids.length > 0 && (method.toLowerCase() === "patch" || method.toLowerCase() === "delete")) {
|
|
73
|
-
const
|
|
99
|
+
const responses = await processBatch(executeOpts.ids, async (id) => {
|
|
74
100
|
const finalPath2 = buildPath(basePath, id);
|
|
75
101
|
return $fetch(finalPath2, {
|
|
76
102
|
baseURL: fullBaseURL,
|
|
@@ -80,12 +106,11 @@ export function useEnfyraApi(path, opts = {}) {
|
|
|
80
106
|
query: finalQuery
|
|
81
107
|
});
|
|
82
108
|
});
|
|
83
|
-
const responses = await Promise.all(promises);
|
|
84
109
|
data.value = responses;
|
|
85
110
|
return responses;
|
|
86
111
|
}
|
|
87
112
|
if (!opts.disableBatch && method.toLowerCase() === "post" && executeOpts?.files && Array.isArray(executeOpts.files) && executeOpts.files.length > 0) {
|
|
88
|
-
const
|
|
113
|
+
const responses = await processBatch(executeOpts.files, async (fileObj) => {
|
|
89
114
|
return $fetch(basePath, {
|
|
90
115
|
baseURL: fullBaseURL,
|
|
91
116
|
method,
|
|
@@ -95,7 +120,6 @@ export function useEnfyraApi(path, opts = {}) {
|
|
|
95
120
|
query: finalQuery
|
|
96
121
|
});
|
|
97
122
|
});
|
|
98
|
-
const responses = await Promise.all(promises);
|
|
99
123
|
data.value = responses;
|
|
100
124
|
return responses;
|
|
101
125
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ export interface ApiOptions<T> {
|
|
|
17
17
|
errorContext?: string;
|
|
18
18
|
onError?: (error: ApiError, context?: string) => void;
|
|
19
19
|
disableBatch?: boolean;
|
|
20
|
+
/** Batch size for chunking large operations (default: no limit) */
|
|
21
|
+
batchSize?: number;
|
|
22
|
+
/** Maximum concurrent requests (default: no limit) */
|
|
23
|
+
concurrent?: number;
|
|
20
24
|
default?: () => T;
|
|
21
25
|
/** Enable SSR with useFetch instead of $fetch */
|
|
22
26
|
ssr?: boolean;
|
|
@@ -46,16 +50,22 @@ export interface UseEnfyraApiSSRReturn<T> extends AsyncData<T | null, ApiError>
|
|
|
46
50
|
error: Ref<ApiError | null>;
|
|
47
51
|
refresh: () => Promise<void>;
|
|
48
52
|
}
|
|
53
|
+
export interface ExecuteOptions {
|
|
54
|
+
body?: any;
|
|
55
|
+
id?: string | number;
|
|
56
|
+
ids?: (string | number)[];
|
|
57
|
+
/** Array of FormData objects for batch upload */
|
|
58
|
+
files?: FormData[];
|
|
59
|
+
/** Override batch size for this specific execution */
|
|
60
|
+
batchSize?: number;
|
|
61
|
+
/** Override concurrent limit for this specific execution */
|
|
62
|
+
concurrent?: number;
|
|
63
|
+
}
|
|
49
64
|
export interface UseEnfyraApiClientReturn<T> {
|
|
50
65
|
data: Ref<T | null>;
|
|
51
66
|
error: Ref<ApiError | null>;
|
|
52
67
|
pending: Ref<boolean>;
|
|
53
|
-
execute: (executeOpts?:
|
|
54
|
-
body?: any;
|
|
55
|
-
id?: string | number;
|
|
56
|
-
ids?: (string | number)[];
|
|
57
|
-
files?: any[];
|
|
58
|
-
}) => Promise<T | T[] | null>;
|
|
68
|
+
execute: (executeOpts?: ExecuteOptions) => Promise<T | T[] | null>;
|
|
59
69
|
}
|
|
60
70
|
export * from './auth';
|
|
61
71
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACnG,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IAClB,iDAAiD;IACjD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,KAAK,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,GAAG,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,MAAM,WAAW,qBAAqB,CAAC,CAAC,CAAE,SAAQ,SAAS,CAAC,CAAC,GAAG,IAAI,EAAE,QAAQ,CAAC;IAC7E,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACpB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACtB,KAAK,EAAE,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC5B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAGD,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/types/index.ts"],"names":[],"mappings":"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"}
|
package/dist/module.json
CHANGED
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
ApiOptions,
|
|
4
4
|
ApiError,
|
|
5
5
|
BackendErrorExtended,
|
|
6
|
+
ExecuteOptions,
|
|
6
7
|
UseEnfyraApiSSRReturn,
|
|
7
8
|
UseEnfyraApiClientReturn,
|
|
8
9
|
} from "../types";
|
|
@@ -46,7 +47,7 @@ export function useEnfyraApi<T = any>(
|
|
|
46
47
|
path: (() => string) | string,
|
|
47
48
|
opts: ApiOptions<T> = {}
|
|
48
49
|
): UseEnfyraApiSSRReturn<T> | UseEnfyraApiClientReturn<T> {
|
|
49
|
-
const { method = "get", body, query, errorContext, onError, ssr, key } = opts;
|
|
50
|
+
const { method = "get", body, query, errorContext, onError, ssr, key, batchSize, concurrent } = opts;
|
|
50
51
|
|
|
51
52
|
// SSR mode - use useFetch
|
|
52
53
|
if (ssr) {
|
|
@@ -101,12 +102,7 @@ export function useEnfyraApi<T = any>(
|
|
|
101
102
|
const error = ref<ApiError | null>(null);
|
|
102
103
|
const pending = ref(false);
|
|
103
104
|
|
|
104
|
-
const execute = async (executeOpts?: {
|
|
105
|
-
body?: any;
|
|
106
|
-
id?: string | number;
|
|
107
|
-
ids?: (string | number)[];
|
|
108
|
-
files?: any[];
|
|
109
|
-
}) => {
|
|
105
|
+
const execute = async (executeOpts?: ExecuteOptions) => {
|
|
110
106
|
pending.value = true;
|
|
111
107
|
error.value = null;
|
|
112
108
|
|
|
@@ -120,6 +116,10 @@ export function useEnfyraApi<T = any>(
|
|
|
120
116
|
.replace(/^\/+/, ""); // Remove leading slashes
|
|
121
117
|
const finalBody = executeOpts?.body || unref(body);
|
|
122
118
|
const finalQuery = unref(query);
|
|
119
|
+
|
|
120
|
+
// Use executeOpts overrides if provided, otherwise fall back to options
|
|
121
|
+
const effectiveBatchSize = executeOpts?.batchSize ?? batchSize;
|
|
122
|
+
const effectiveConcurrent = executeOpts?.concurrent ?? concurrent;
|
|
123
123
|
|
|
124
124
|
// Helper function to build clean path
|
|
125
125
|
const buildPath = (...segments: (string | number)[]): string => {
|
|
@@ -129,6 +129,44 @@ export function useEnfyraApi<T = any>(
|
|
|
129
129
|
// Build full base URL with prefix
|
|
130
130
|
const fullBaseURL = apiUrl + (apiPrefix || "");
|
|
131
131
|
|
|
132
|
+
// Helper function for batch processing with chunking and concurrency control
|
|
133
|
+
async function processBatch<T>(
|
|
134
|
+
items: any[],
|
|
135
|
+
processor: (item: any) => Promise<T>
|
|
136
|
+
): Promise<T[]> {
|
|
137
|
+
const results: T[] = [];
|
|
138
|
+
|
|
139
|
+
// If no limits, process all at once (current behavior)
|
|
140
|
+
if (!effectiveBatchSize && !effectiveConcurrent) {
|
|
141
|
+
const promises = items.map(processor);
|
|
142
|
+
return await Promise.all(promises);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Chunk items by batchSize
|
|
146
|
+
const chunks = effectiveBatchSize ?
|
|
147
|
+
Array.from({ length: Math.ceil(items.length / effectiveBatchSize) }, (_, i) =>
|
|
148
|
+
items.slice(i * effectiveBatchSize, i * effectiveBatchSize + effectiveBatchSize)
|
|
149
|
+
) : [items];
|
|
150
|
+
|
|
151
|
+
// Process each chunk
|
|
152
|
+
for (const chunk of chunks) {
|
|
153
|
+
if (effectiveConcurrent && chunk.length > effectiveConcurrent) {
|
|
154
|
+
// Process chunk with concurrency limit
|
|
155
|
+
for (let i = 0; i < chunk.length; i += effectiveConcurrent) {
|
|
156
|
+
const batch = chunk.slice(i, i + effectiveConcurrent);
|
|
157
|
+
const batchResults = await Promise.all(batch.map(processor));
|
|
158
|
+
results.push(...batchResults);
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
// Process entire chunk at once
|
|
162
|
+
const chunkResults = await Promise.all(chunk.map(processor));
|
|
163
|
+
results.push(...chunkResults);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return results;
|
|
168
|
+
}
|
|
169
|
+
|
|
132
170
|
// Batch operation with multiple IDs (only for patch and delete)
|
|
133
171
|
if (
|
|
134
172
|
!opts.disableBatch &&
|
|
@@ -136,7 +174,7 @@ export function useEnfyraApi<T = any>(
|
|
|
136
174
|
executeOpts.ids.length > 0 &&
|
|
137
175
|
(method.toLowerCase() === "patch" || method.toLowerCase() === "delete")
|
|
138
176
|
) {
|
|
139
|
-
const
|
|
177
|
+
const responses = await processBatch(executeOpts.ids, async (id) => {
|
|
140
178
|
const finalPath = buildPath(basePath, id);
|
|
141
179
|
return $fetch<T>(finalPath, {
|
|
142
180
|
baseURL: fullBaseURL,
|
|
@@ -147,7 +185,6 @@ export function useEnfyraApi<T = any>(
|
|
|
147
185
|
});
|
|
148
186
|
});
|
|
149
187
|
|
|
150
|
-
const responses = await Promise.all(promises);
|
|
151
188
|
data.value = responses as T;
|
|
152
189
|
return responses;
|
|
153
190
|
}
|
|
@@ -160,7 +197,7 @@ export function useEnfyraApi<T = any>(
|
|
|
160
197
|
Array.isArray(executeOpts.files) &&
|
|
161
198
|
executeOpts.files.length > 0
|
|
162
199
|
) {
|
|
163
|
-
const
|
|
200
|
+
const responses = await processBatch(executeOpts.files, async (fileObj: any) => {
|
|
164
201
|
return $fetch<T>(basePath, {
|
|
165
202
|
baseURL: fullBaseURL,
|
|
166
203
|
method: method as any,
|
|
@@ -170,7 +207,6 @@ export function useEnfyraApi<T = any>(
|
|
|
170
207
|
});
|
|
171
208
|
});
|
|
172
209
|
|
|
173
|
-
const responses = await Promise.all(promises);
|
|
174
210
|
data.value = responses as T;
|
|
175
211
|
return responses;
|
|
176
212
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -19,6 +19,10 @@ export interface ApiOptions<T> {
|
|
|
19
19
|
errorContext?: string;
|
|
20
20
|
onError?: (error: ApiError, context?: string) => void;
|
|
21
21
|
disableBatch?: boolean;
|
|
22
|
+
/** Batch size for chunking large operations (default: no limit) */
|
|
23
|
+
batchSize?: number;
|
|
24
|
+
/** Maximum concurrent requests (default: no limit) */
|
|
25
|
+
concurrent?: number;
|
|
22
26
|
default?: () => T;
|
|
23
27
|
/** Enable SSR with useFetch instead of $fetch */
|
|
24
28
|
ssr?: boolean;
|
|
@@ -54,17 +58,25 @@ export interface UseEnfyraApiSSRReturn<T> extends AsyncData<T | null, ApiError>
|
|
|
54
58
|
refresh: () => Promise<void>;
|
|
55
59
|
}
|
|
56
60
|
|
|
61
|
+
// Execute options interface
|
|
62
|
+
export interface ExecuteOptions {
|
|
63
|
+
body?: any;
|
|
64
|
+
id?: string | number;
|
|
65
|
+
ids?: (string | number)[];
|
|
66
|
+
/** Array of FormData objects for batch upload */
|
|
67
|
+
files?: FormData[];
|
|
68
|
+
/** Override batch size for this specific execution */
|
|
69
|
+
batchSize?: number;
|
|
70
|
+
/** Override concurrent limit for this specific execution */
|
|
71
|
+
concurrent?: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
57
74
|
// Client Mode return type
|
|
58
75
|
export interface UseEnfyraApiClientReturn<T> {
|
|
59
76
|
data: Ref<T | null>;
|
|
60
77
|
error: Ref<ApiError | null>;
|
|
61
78
|
pending: Ref<boolean>;
|
|
62
|
-
execute: (executeOpts?:
|
|
63
|
-
body?: any;
|
|
64
|
-
id?: string | number;
|
|
65
|
-
ids?: (string | number)[];
|
|
66
|
-
files?: any[];
|
|
67
|
-
}) => Promise<T | T[] | null>;
|
|
79
|
+
execute: (executeOpts?: ExecuteOptions) => Promise<T | T[] | null>;
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
|