Something went wrong. Try again.
Monorepo for Tangled forked from tangled.org/core
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081import { untrack } from "svelte";
type ActionState<T> = | { kind: "idle" } | { kind: "loading" } | { kind: "ready"; value: T } | { kind: "failed"; error: string; cause: unknown };type Operation<T, Args extends unknown[] = []> = (...args: Args) => Promise<T>;
const defaultError = (cause: unknown) => (cause instanceof Error ? cause.message : String(cause));
const create = <T, Args extends unknown[] = []>( operation: Operation<T, Args>, initial: ActionState<T>, toError: typeof defaultError) => { let state = $state<ActionState<T>>(initial); let revision = 0; let args: Args | undefined;
const run: Operation<void, Args> = async (...nextArgs) => { const currentRevision = ++revision; args = nextArgs; if (untrack(() => state.kind) !== "loading") state = { kind: "loading" }; try { const value = await operation(...nextArgs); if (currentRevision !== revision) return; args = undefined; state = { kind: "ready", value }; } catch (cause) { if (currentRevision !== revision) return; args = undefined; state = { kind: "failed", error: toError(cause), cause }; } };
return { get data() { return state.kind === "ready" ? state.value : undefined; }, get error() { return state.kind === "failed" ? state.error : undefined; }, get cause() { return state.kind === "failed" ? state.cause : undefined; }, get loading() { return state.kind === "loading"; }, get args() { return state.kind === "loading" ? args : undefined; }, run, update(update: (current: T) => T): boolean { if (state.kind !== "ready") return false; revision++; state = { kind: "ready", value: update(state.value) }; return true; } };};
// loads run automatically and rerun when reactive values change:// const post = createLoad(() => api.getPost(id));//// actions only run when called:// const save = createAction(api.savePost);// await save.run(draft);//// both expose .data, .error, .loading, and .args.export const createAction = <T, Args extends unknown[] = []>( operation: Operation<T, Args>, toError: typeof defaultError = defaultError) => create(operation, { kind: "idle" }, toError);
export const createLoad = <T>(load: Operation<T>, toError: typeof defaultError = defaultError) => { const action = create(load, { kind: "loading" }, toError); $effect(() => void action.run()); return action;};