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.**

155 lines 4.12 kB
import { DefaultValyncClient } from "./util.js"; export { DefaultValyncClient }; // Normalize cache key (convert object to stable string) export function normalizeKey(key) { if (typeof key === "string") return key; const { url, ...params } = key; const search = new URLSearchParams(params); return `${url}?${search.toString()}`; } export class AsyncObserver { constructor(_current) { this._current = _current; this.listeners = new Set(); this.observer = this.observer.bind(this); this.listen = this.listen.bind(this); this.removeListener = this.removeListener.bind(this); } listen(fn) { fn(this._current); this.listeners.add(fn); return; } removeListener(fn) { return this.listeners.delete(fn); } observer() { return { addListener: this.listen, removeListener: this.removeListener, }; } set(val) { this._current = val; this.listeners.forEach((fn) => fn(val)); } } // Base abstract class for async state export class AsyncValue { isLoading() { return this instanceof AsyncLoading; } isData() { return this instanceof AsyncData; } isError() { return this instanceof AsyncError; } } // Represents loading state export class AsyncLoading extends AsyncValue { when(h) { return (h.loading ? h.loading() : undefined); } unwrap() { throw new Error("unwrap on loading"); } unwrapErr() { throw new Error("unwrapErr on loading"); } } // Represents failed state with error export class AsyncError extends AsyncValue { constructor(error) { super(); this.error = error; } when(h) { return (h.error ? h.error(this.error) : undefined); } unwrap() { throw new Error("unwrap on Err"); } unwrapErr() { return this.error; } } // Represents data state—with Some(T) or None export class AsyncData extends AsyncValue { constructor(value) { super(); this.value = value; } when(h) { return (h.data ? h.data(this.value) : undefined); } unwrap() { return this.value; } unwrapErr() { throw new Error("unwrapErr on loading"); } } function isPlainObject(v) { if (v === null || typeof v !== "object") return false; if (v instanceof Blob) return false; if (v instanceof FormData) return false; if (v instanceof URLSearchParams) return false; if (v instanceof ArrayBuffer) return false; if (typeof ReadableStream !== "undefined" && v instanceof ReadableStream) return false; return true; } export function buildRequestBody(body, files) { if (files?.length) { const fd = body instanceof FormData ? body : new FormData(); if (body && !(body instanceof FormData) && isPlainObject(body)) { for (const [k, v] of Object.entries(body)) { fd.append(k, String(v)); } } for (const file of files) { if (Array.isArray(file)) { fd.append(file[0], file[1]); } else { fd.append("file", file); } } return { body: fd, isMultipart: true }; } if (body instanceof FormData) { return { body, isMultipart: true }; } if (isPlainObject(body)) { return { body: JSON.stringify(body), isMultipart: false }; } return { body: body, isMultipart: false }; } export function mergeHeaders(base, extra) { const result = {}; const append = (h) => { if (!h) return; if (h instanceof Headers) { h.forEach((v, k) => (result[k] = v)); } else if (Array.isArray(h)) { for (const [k, v] of h) result[k] = v; } else { Object.assign(result, h); } }; append(base); append(extra); return result; } //# sourceMappingURL=index.js.map