UNPKG

valync

Version:

**A lightweight, framework-agnostic async data handling library for React & Vue, inspired by Riverpod’s AsyncValue pattern and powered by ts-results-es.**

201 lines 7.42 kB
import { ref, onMounted, watch } from "vue"; import { Some, None } from "ts-results-es"; import { normalizeKey, AsyncLoading, AsyncError, AsyncData, } from "../core"; const cache = new Map(); export function createValyn({ client, }) { return function (key, options = {}) { const keyStr = normalizeKey(key); const controller = ref(); let initialValue; if (options.initialData) { initialValue = options.initialData.status === "success" ? new AsyncData(Some(options.initialData.data)) : new AsyncError(options.initialData.error); } else if (options.cache !== false && cache.has(keyStr)) { initialValue = cache.get(keyStr); } else { initialValue = new AsyncData(None); } const state = ref(initialValue); const isClient = typeof window !== "undefined" && typeof AbortController !== "undefined"; const doFetch = () => { controller.value?.abort(); controller.value = new AbortController(); if (options.cache !== false && cache.has(keyStr)) { state.value = cache.get(keyStr); return; } state.value = new AsyncLoading(); const attempt = (tries) => { client(typeof key === "string" ? key : keyStr, { ...options.init, signal: controller.value.signal, }) .then((res) => { if (controller.value.signal.aborted) return; if (res.status === "failed") state.value = new AsyncError(res.error); else { const data = options.onData ? options.onData(res.data) : res.data; const sd = new AsyncData(Some(data)); if (options.cache !== false) cache.set(keyStr, sd); state.value = sd; } }) .catch((err) => { if (controller.value.signal.aborted) return; if (tries > 0) return attempt(tries - 1); state.value = new AsyncError({ name: "NetworkError", message: err.message, code: "500", }); }); }; attempt(options.retryCount ?? 0); }; if (isClient && options.fetchOnMount !== false && !options.initialData) { onMounted(doFetch); } if (isClient && options.watch && options.watch.length > 0) { watch(options.watch, doFetch); } const refetch = () => { if (isClient) doFetch(); }; const setData = (updater) => { const currentVal = state.value instanceof AsyncData ? state.value.value.isSome() ? state.value.value.unwrap() : null : null; const newVal = new AsyncData(Some(updater(currentVal))); if (options.cache !== false) cache.set(keyStr, newVal); state.value = newVal; }; return [state.value, refetch, setData]; }; } export function useValync(key, options = {}) { const keyStr = normalizeKey(key); const controller = ref(); let initialValue; if (options.initialData) { initialValue = options.initialData.status === "success" ? new AsyncData(Some(options.initialData.data)) : new AsyncError(options.initialData.error); } else if (options.cache !== false && cache.has(keyStr)) { initialValue = cache.get(keyStr); } else { initialValue = new AsyncData(None); } const state = ref(initialValue); const isClient = typeof window !== "undefined" && typeof AbortController !== "undefined"; const doFetch = () => { controller.value?.abort(); controller.value = new AbortController(); if (options.cache !== false && cache.has(keyStr)) { state.value = cache.get(keyStr); return; } state.value = new AsyncLoading(); const attempt = (tries) => { fetch(typeof key === "string" ? key : keyStr, { ...options.init, signal: controller.value.signal, }) .then(async (resp) => { let json; try { json = await resp.json(); } catch { return { status: "failed", error: { name: "ParseError", message: "Invalid JSON", }, }; } if (!resp.ok || json.status === "failed") { return { status: "failed", error: json.error ?? { name: "HttpError", message: resp.statusText, code: resp.status, }, }; } return json; }) .then((res) => { if (controller.value.signal.aborted) return; if (res.status === "failed") state.value = new AsyncError(res.error); else { const data = options.onData ? options.onData(res.data) : res.data; const sd = new AsyncData(Some(data)); if (options.cache !== false) cache.set(keyStr, sd); state.value = sd; } }) .catch((err) => { if (controller.value.signal.aborted) return; if (tries > 0) return attempt(tries - 1); state.value = new AsyncError({ name: "NetworkError", message: err.message, }); }); }; attempt(options.retryCount ?? 0); }; if (isClient && options.fetchOnMount !== false && !options.initialData) { onMounted(doFetch); } if (isClient && options.watch && options.watch.length > 0) { watch(options.watch, doFetch); } const refetch = () => { if (isClient) doFetch(); }; const setData = (updater) => { const currentVal = state.value instanceof AsyncData ? state.value.value.isSome() ? state.value.value.unwrap() : null : null; const newVal = new AsyncData(Some(updater(currentVal))); if (options.cache !== false) cache.set(keyStr, newVal); state.value = newVal; }; return [state.value, refetch, setData]; } //# sourceMappingURL=index.js.map