import type { AbstractCrdtDocFactory, InferDocLike } from "@pluv/crdt"; import type { EventRecord, IOLike, InputZodLike, JsonObject, ProcedureLike } from "@pluv/types"; import type { EventResolver, MergeEventRecords } from "./types"; export interface PluvProcedureConfig< TIO extends IOLike, TInput extends JsonObject, TOutput extends EventRecord, TPresence extends Record, TCrdt extends AbstractCrdtDocFactory, > { broadcast?: EventResolver> | null; input?: InputZodLike; } export class PluvProcedure< TIO extends IOLike, TInput extends JsonObject, TOutput extends EventRecord, TPresence extends Record, TCrdt extends AbstractCrdtDocFactory, TFilled extends "input" | "broadcast" | "", > implements ProcedureLike { private _broadcast: EventResolver< TIO, TInput, Partial, TPresence, InferDocLike > | null = null; private _input: InputZodLike | null = null; public get config(): ProcedureLike["config"] { return { broadcast: this._broadcast?.bind(this) ?? null, input: this._input ?? null, resolver: this._resolver(), } as ProcedureLike["config"]; } constructor(config: PluvProcedureConfig = {}) { const { broadcast, input } = config; this._broadcast = broadcast ?? null; this._input = input ?? null; } public broadcast = {}>( resolver: EventResolver>, ): Omit< PluvProcedure< TIO, TInput, MergeEventRecords<[TOutput, TResult]>, TPresence, TCrdt, TFilled | "input" | "broadcast" >, TFilled | "input" | "broadcast" > { const { broadcast } = this.config; if (!!broadcast) throw new Error("Broadcast was already defined for this procedure"); return new PluvProcedure< TIO, TInput, MergeEventRecords<[TOutput, TResult]>, TPresence, TCrdt, TFilled | "input" | "broadcast" >({ ...(this.config as any), broadcast: resolver as any, }); } public input( input: InputZodLike, ): Omit, TFilled | "input"> { return new PluvProcedure({ input }); } private _resolver(): EventResolver> { return (data, context) => this._broadcast?.(data, context) as TOutput; } }