This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / web / src / lib / action.svelte.ts
2.2 kB 75 lines
1type ActionState<T> = 2 | { kind: "idle" } 3 | { kind: "loading" } 4 | { kind: "ready"; value: T } 5 | { kind: "failed"; error: string }; 6type Operation<T, Args extends unknown[] = []> = (...args: Args) => Promise<T>; 7 8const defaultError = (cause: unknown) => (cause instanceof Error ? cause.message : String(cause)); 9 10const create = <T, Args extends unknown[] = []>( 11 operation: Operation<T, Args>, 12 initial: ActionState<T>, 13 toError: typeof defaultError 14) => { 15 let state = $state<ActionState<T>>(initial); 16 let revision = 0; 17 let args: Args | undefined; 18 19 const run: Operation<void, Args> = async (...nextArgs) => { 20 const currentRevision = ++revision; 21 args = nextArgs; 22 state = { kind: "loading" }; 23 try { 24 const value = await operation(...nextArgs); 25 if (currentRevision !== revision) return; 26 args = undefined; 27 state = { kind: "ready", value }; 28 } catch (cause) { 29 if (currentRevision !== revision) return; 30 args = undefined; 31 state = { kind: "failed", error: toError(cause) }; 32 } 33 }; 34 35 return { 36 get data() { 37 return state.kind === "ready" ? state.value : undefined; 38 }, 39 get error() { 40 return state.kind === "failed" ? state.error : undefined; 41 }, 42 get loading() { 43 return state.kind === "loading"; 44 }, 45 get args() { 46 return state.kind === "loading" ? args : undefined; 47 }, 48 run, 49 update(update: (current: T) => T): boolean { 50 if (state.kind !== "ready") return false; 51 revision++; 52 state = { kind: "ready", value: update(state.value) }; 53 return true; 54 } 55 }; 56}; 57 58// loads run automatically and rerun when reactive values change: 59// const post = createLoad(() => api.getPost(id)); 60// 61// actions only run when called: 62// const save = createAction(api.savePost); 63// await save.run(draft); 64// 65// both expose .data, .error, .loading, and .args. 66export const createAction = <T, Args extends unknown[] = []>( 67 operation: Operation<T, Args>, 68 toError: typeof defaultError = defaultError 69) => create(operation, { kind: "idle" }, toError); 70 71export const createLoad = <T>(load: Operation<T>, toError: typeof defaultError = defaultError) => { 72 const action = create(load, { kind: "loading" }, toError); 73 $effect(() => void action.run()); 74 return action; 75};