import { Req, Services, Sub } from "./services"; import { Signal, Subscription, Value } from "./signal"; export const program = (options: Program.Options) => new Program(options); /** Internals */ export class Program { private readonly state$: Value; private readonly message$: Signal; private readonly services: Services; constructor(options: Program.Options) { const { init, update, subscriptions, env = {} } = options; const { state: initialState, requests: initialRequests = [] } = init(); this.state$ = new Value(initialState); this.message$ = new Signal(); this.services = new Services(this.update, env); this.message$.subscribe((message) => { const { state, requests = [] } = update(this.state$.value, message); this.state$.value = state; this.services.handleRequests(requests); this.services.updateSubscriptions(subscriptions ? subscriptions(state) : []); }); this.services.handleRequests(initialRequests); this.services.updateSubscriptions(subscriptions ? subscriptions(initialState) : []); } get state() { return this.state$.value; } public update = (message: Message) => { this.message$.emit(message); } public observe = (observer: (state: State) => void): Subscription => { return this.state$.subscribe(observer); } } /** Types */ export namespace Program { export interface Options { readonly env?: Record; init(): Next; update(state: State, message: Message): Next; subscriptions?(state: State): ReadonlyArray>; } } export interface Next { state: State; requests?: ReadonlyArray>; } export type Dispatch = (message: Message) => void;