import { SEQUENCER_MEDIA_REVISION_SCHEMA, gateSequencerMediaRevision, parseSequencerMediaRevisionRequest, parseSequencerMediaRevisionState, SequencerMediaRevisionValidationError, type SequencerMediaOperation, type SequencerMediaRevisionDecisionIR, type SequencerMediaRevisionRequestIR, type SequencerMediaRevisionResultIR, type SequencerMediaRevisionStateIR, } from "../../../protocol/sequencer-media-revision"; export class SequencerMediaRevisionGate { private stateValue: SequencerMediaRevisionStateIR; constructor(timelineId: string, timelineRevision: number) { this.stateValue = parseSequencerMediaRevisionState({ schemaVersion: SEQUENCER_MEDIA_REVISION_SCHEMA, timelineId, timelineRevision, latestRequestRevision: 0, }); } state(): SequencerMediaRevisionStateIR { return { ...this.stateValue }; } begin(operation: SequencerMediaOperation, frame: number): SequencerMediaRevisionRequestIR { this.stateValue = { ...this.stateValue, latestRequestRevision: this.stateValue.latestRequestRevision + 1, }; return parseSequencerMediaRevisionRequest({ schemaVersion: SEQUENCER_MEDIA_REVISION_SCHEMA, requestId: `media:${this.stateValue.latestRequestRevision}`, timelineId: this.stateValue.timelineId, timelineRevision: this.stateValue.timelineRevision, requestRevision: this.stateValue.latestRequestRevision, operation, frame, }); } replaceTimeline(timelineId: string, timelineRevision: number): SequencerMediaRevisionStateIR { if (timelineId === this.stateValue.timelineId && timelineRevision <= this.stateValue.timelineRevision) { throw new SequencerMediaRevisionValidationError("REVISION_CONFLICT", "Sequencer timeline revision must advance monotonically"); } this.stateValue = parseSequencerMediaRevisionState({ schemaVersion: SEQUENCER_MEDIA_REVISION_SCHEMA, timelineId, timelineRevision, latestRequestRevision: this.stateValue.latestRequestRevision + 1, }); return this.state(); } resolve( request: SequencerMediaRevisionRequestIR, result: SequencerMediaRevisionResultIR, publish: (result: SequencerMediaRevisionResultIR) => void, ): SequencerMediaRevisionDecisionIR { const decision = gateSequencerMediaRevision(request, this.stateValue, result); if (decision.status === "PUBLISH") publish(result); return decision; } } export type { SequencerMediaOperation, SequencerMediaRevisionDecisionIR, SequencerMediaRevisionRequestIR, SequencerMediaRevisionResultIR, SequencerMediaRevisionStateIR, };