import { PathMapper } from "./path-mapper" ; import { Model , CompletionBatch , Snapshot , Sync , CompletionError , CommandCompletion , Interceptor } from "./types" ; import { applyCompletions } from "./functions" ; import { Inner } from "./inner" ; export interface ApplyResult < T extends object > { applied : CompletionBatch ; sync ? : Sync < T > ; errors ? : CompletionError [ ] ; } export interface MasterConfig < T extends object , C > { historyProvider ? : HistoryProvider ; interceptor ? : Interceptor < T , C > ; sequentialIds ? : boolean ; } /**
 * Returns the command history between the specified command counts, if available, otherwise returns undefined
 */ export type HistoryProvider = ( from : number , to : number ) => Promise < CommandCompletion [ ] | undefined > ; /**
 * Updates the master model and responds to flush batches, providing diffs from an optional
 * history provider.
 */ export class Master < T extends object , C = unknown > { private readonly historyProvider ? : HistoryProvider ; private readonly model : Model < T > ; private readonly interceptor ? : Interceptor < T , C > ; constructor ( snapshot , config ? ) { this . model = new Inner ( snapshot , config ? ! ! config . sequentialIds : false ) ; this . historyProvider = config ? config . historyProvider : undefined ; this . interceptor = config ? config . interceptor : undefined ; } public getSnapshot ( ) { return { commandCount : this . model . getCommandCount ( ) , document : this . model . getDocument ( ) } ; } param batch public async apply ( batch , context ? ) { const startUpdate = this . model . getCommandCount ( ) ; const pathMapper = new PathMapper ( ) ; const result = applyCompletions ( this . model , batch . completions , pathMapper , this . interceptor , context ) ; const needsSync = batch . from !== startUpdate || result != undefined ; const applied = { from : startUpdate , completions : result == undefined ? batch . completions : result . applied . completions } ; let sync ; if ( needsSync ) { const needsHistory = batch . from !== startUpdate ; let historyDiff ; if ( needsHistory ) { historyDiff = this . historyProvider ? await this . historyProvider ( batch . from , startUpdate ) : undefined ; } if ( needsHistory && ( historyDiff == undefined || historyDiff . length !== startUpdate - batch . from ) ) { sync = { isPartial : false , mappedPaths : pathMapper . getMappings ( ) , latest : this . getSnapshot ( ) } ; } else { const diff = { from : batch . from , completions : historyDiff ? historyDiff . concat ( applied . completions ) : applied . completions } ; sync = { isPartial : true , diff , mappedPaths : pathMapper . getMappings ( ) } ; } } return { sync , applied , errors : result == undefined ? undefined : result . errors } ; } }