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
JavaScript
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