import { ref } from "vue";
/**
* Composable for managing async request lifecycle:
* isLoading, error, and AbortController cancellation.
*
* @param {Object} options
* @param {boolean} options.ignoreTimeout – when true (default), timeout errors
* are NOT written to `error` because they usually come from request
* cancellation on route leave / modal close.
*/
export function useAsyncRequest(options = {}) {
const abortController = ref(null);
const isLoading = ref(false);
const error = ref(null);
async function execute(apiCall) {
abortController.value?.abort();
const controller = new AbortController();
abortController.value = controller;
isLoading.value = true;
error.value = null;
try {
const result = await apiCall(controller.signal);
abortController.value = null;
isLoading.value = false;
if (!result.ok) {
if (options.ignoreTimeout !== false && result.error?.type === "timeout") {
return result;
}
error.value = result.error;
return result;
}
return result;
} catch (err) {
abortController.value = null;
isLoading.value = false;
error.value = {
type: "network_error",
message: err?.message || "Network error",
};
return { ok: false, error: error.value };
}
}
function abort() {
abortController.value?.abort();
abortController.value = null;
}
function clear() {
error.value = null;
abort();
}
return {
abortController,
isLoading,
error,
execute,
abort,
clear,
};
}