[READ ONLY MIRROR] Spark Social AppView Server github.com/sprksocial/server
atproto deno hono lexicon
1
fork

Configure Feed

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

at main 106 lines 3.2 kB view raw
1import { mapDefined } from "@atp/common"; 2import { HydrationState } from "./hydration/index.ts"; 3 4export type SkeletonFn<Context, Params, Skeleton> = ( 5 input: SkeletonFnInput<Context, Params>, 6) => Promise<Skeleton> | Skeleton; 7 8export type HydrationFn<Context, Params, Skeleton> = ( 9 input: HydrationFnInput<Context, Params, Skeleton>, 10) => Promise<HydrationState>; 11 12export type RulesFn<Context, Params, Skeleton> = ( 13 input: RulesFnInput<Context, Params, Skeleton>, 14) => Skeleton; 15 16export type PresentationFn<Context, Params, Skeleton, View> = ( 17 input: PresentationFnInput<Context, Params, Skeleton>, 18) => View; 19 20export type PipelineDefinition<Params, Skeleton, View, Context> = { 21 skeleton: SkeletonFn<Context, Params, Skeleton>; 22 hydration: HydrationFn<Context, Params, Skeleton>; 23 rules?: RulesFn<Context, Params, Skeleton>; 24 presentation: PresentationFn<Context, Params, Skeleton, View>; 25}; 26 27export function createPipeline<Params, Skeleton, View, Context>( 28 definition: PipelineDefinition<Params, Skeleton, View, Context>, 29): (params: Params, ctx: Context) => Promise<View>; 30export function createPipeline<Params, Skeleton, View, Context>( 31 definition: PipelineDefinition<Params, Skeleton, View, Context>, 32) { 33 const applyRules = definition.rules ?? 34 ((input: RulesFnInput<Context, Params, Skeleton>) => input.skeleton); 35 36 return async (params: Params, ctx: Context) => { 37 const skeleton = await definition.skeleton({ ctx, params }); 38 const hydration = await definition.hydration({ ctx, params, skeleton }); 39 const appliedRules = applyRules({ ctx, params, skeleton, hydration }); 40 return definition.presentation({ 41 ctx, 42 params, 43 skeleton: appliedRules, 44 hydration, 45 }); 46 }; 47} 48 49export type SkeletonFnInput<Context, Params> = { 50 ctx: Context; 51 params: Params; 52}; 53 54export type HydrationFnInput<Context, Params, Skeleton> = { 55 ctx: Context; 56 params: Params; 57 skeleton: Skeleton; 58}; 59 60export type RulesFnInput<Context, Params, Skeleton> = { 61 ctx: Context; 62 params: Params; 63 skeleton: Skeleton; 64 hydration: HydrationState; 65}; 66 67export type PresentationFnInput<Context, Params, Skeleton> = { 68 ctx: Context; 69 params: Params; 70 skeleton: Skeleton; 71 hydration: HydrationState; 72}; 73 74type SkeletonListKey<S> = { 75 [K in keyof S]: S[K] extends readonly unknown[] ? K : never; 76}[keyof S]; 77 78type SkeletonListItem<T> = T extends readonly (infer Item)[] ? Item : never; 79 80export function filterSkeletonList< 81 Skeleton extends Record<string, unknown>, 82 Key extends SkeletonListKey<Skeleton>, 83>( 84 skeleton: Skeleton, 85 key: Key, 86 predicate: (item: SkeletonListItem<Skeleton[Key]>) => boolean, 87): Skeleton { 88 const items = skeleton[key] as SkeletonListItem<Skeleton[Key]>[]; 89 return { 90 ...skeleton, 91 [key]: items.filter(predicate), 92 } as Skeleton; 93} 94 95export function mapSkeletonList< 96 Skeleton extends Record<string, unknown>, 97 Key extends SkeletonListKey<Skeleton>, 98 View, 99>( 100 skeleton: Skeleton, 101 key: Key, 102 mapper: (item: SkeletonListItem<Skeleton[Key]>) => View | undefined, 103): View[] { 104 const items = skeleton[key] as SkeletonListItem<Skeleton[Key]>[]; 105 return mapDefined(items, mapper); 106}