@mengine/medeo-client 2.0.1-alpha.6 → 2.0.1-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -442,10 +442,6 @@ interface VideoDraft$1 {
442
442
  }
443
443
  //#endregion
444
444
  //#region src/document/types.d.ts
445
- declare const VIDEO_DOCUMENT_SCHEMA_VERSION: "video-document/v0";
446
- /** A server-derived compatibility view, never an editor write authority. */
447
- declare const ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION: "video-document/entity-projection-v1";
448
- type VideoDocumentSchemaVersion = typeof VIDEO_DOCUMENT_SCHEMA_VERSION | typeof ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION;
449
445
  type PartKind = 'video_clip' | 'speech' | 'caption' | 'bgm';
450
446
  /**
451
447
  * Project-level creation settings. Mirrors the IDL, but keeps the two fields the
@@ -645,17 +641,52 @@ type VideoDraftPartUnion = {
645
641
  };
646
642
  };
647
643
  /**
648
- * Derived `VideoDraft` read-view. The shape follows the IDL verbatim except for
649
- * `part_library`: the IDL types its parts with the generated namespace
650
- * `PartUnion`, but the engine's projection emits `VideoDraftPartUnion` — the
651
- * authoritative parts with the derived `duration_ms` re-injected (reference/17 §7)
652
- * plus the engine extensions (`media_duration_ms`, the looser `SpeedShift`). This
653
- * is the intentional superset over the IDL `VideoDraft` (see the extensions note).
644
+ * Legacy Draft import shape. It allows omitted durations and engine extensions
645
+ * so existing fixtures and migrations can state only the facts they have.
646
+ * Projection returns the narrower `VideoDraftContent` contract instead.
654
647
  */
655
648
  type VideoDraft = Omit<VideoDraft$1, 'part_library' | 'video_creation_settings'> & {
656
649
  part_library: Record<string, VideoDraftPartUnion> | undefined;
657
650
  video_creation_settings?: VideoCreationSettings | undefined;
658
651
  };
652
+ /**
653
+ * The complete content read model produced by the shared projection. Business
654
+ * identity, settings, thumbnail and revision counters are assembled by Director;
655
+ * keeping an explicit field list prevents new business DTO fields entering here.
656
+ */
657
+ type VideoDraftContent = Pick<VideoDraft, 'timeline' | 'main_track' | 'above_main_tracks' | 'below_main_tracks' | 'part_aggregations'> & {
658
+ part_library: Record<string, VideoDraftContentPartUnion> | undefined;
659
+ };
660
+ /** Projection always states the duration field; legacy imports may omit it. */
661
+ type VideoDraftContentPartUnion = {
662
+ video_clip: VideoClipPart & {
663
+ duration_ms: number | undefined;
664
+ };
665
+ speech?: never;
666
+ caption?: never;
667
+ bgm?: never;
668
+ } | {
669
+ video_clip?: never;
670
+ speech: SpeechPart & {
671
+ duration_ms: number | undefined;
672
+ };
673
+ caption?: never;
674
+ bgm?: never;
675
+ } | {
676
+ video_clip?: never;
677
+ speech?: never;
678
+ caption: CaptionPart & {
679
+ duration_ms: number | undefined;
680
+ };
681
+ bgm?: never;
682
+ } | {
683
+ video_clip?: never;
684
+ speech?: never;
685
+ caption?: never;
686
+ bgm: BgmPart & {
687
+ duration_ms: number | undefined;
688
+ };
689
+ };
659
690
  /** Authoritative timeline: `duration_ms` is derived (= longest track), not stored. */
660
691
  interface Timeline {
661
692
  unit_time_ms: number | undefined;
@@ -670,39 +701,19 @@ interface Timeline {
670
701
  * is not, and passes any `>= 0` guard on its way to an editor that cannot use it.
671
702
  */
672
703
  declare const DEFAULT_UNIT_TIME_MS = 33.333;
673
- /**
674
- * Project-level scalars that do not participate in track ordering. Grouped under
675
- * `meta` because the loro-mirror `schema()` root only accepts container schemas,
676
- * not bare scalars — so these must live inside a map container in storage. The
677
- * domain type mirrors that storage shape 1:1 (RFC 03 §4) rather than flattening,
678
- * keeping `VideoDocument` and the loro draft isomorphic and the mapping layer a
679
- * near-identity. `schema_version` lives here too (it is a scalar fact).
680
- */
681
- interface VideoDocumentMeta {
682
- schema_version: VideoDocumentSchemaVersion;
683
- draft_id?: string | undefined;
684
- project_id: VideoDraft['project_id'];
685
- owner_id: VideoDraft['owner_id'];
686
- thumbnail_storage_key: VideoDraft['thumbnail_storage_key'];
687
- chat_session_id: VideoDraft['chat_session_id'];
688
- video_creation_settings: VideoDraft['video_creation_settings'];
689
- /** Legacy imported version for v0; committed Entity revision for entity-projection-v1. */
690
- version: VideoDraft['version'];
691
- }
692
704
  /**
693
705
  * Authoritative collaborative document: only facts. Positioning lives on each
694
706
  * `TrackItem.time_position`; absolute time, `part_aggregations`, and total
695
707
  * duration are derived in the `VideoDraft` projection, not stored here (RFC 02 §6).
696
708
  *
697
- * The shape mirrors the loro storage structure 1:1 (RFC 03 §4): a `meta` map of
698
- * project scalars, plus a single ordered `tracks` list (reference/17 §4). A
709
+ * The content mirrors Loro storage: timeline, part library, and a single
710
+ * ordered `tracks` list (reference/17 §4). Business metadata stays in Director. A
699
711
  * track's lane is expressed by its `parts_kind`, not by which container it lives
700
712
  * in — the `main` / `above` / `below` three-pane view is reconstructed at
701
713
  * projection time. Order is the list order itself, so there is no `lane` /
702
714
  * `lane_order` field to diverge under concurrent edits.
703
715
  */
704
716
  interface VideoDocument {
705
- meta: VideoDocumentMeta;
706
717
  timeline: Timeline | undefined;
707
718
  tracks: Track[] | undefined;
708
719
  part_library: Record<string, PartUnion> | undefined;
@@ -724,15 +735,193 @@ interface VideoDocumentValidationIssue {
724
735
  severity?: VideoDocumentValidationIssueSeverity;
725
736
  }
726
737
  //#endregion
738
+ //#region src/document/mirror-schema.d.ts
739
+ declare const videoDocumentMirrorSchema: import("loro-mirror").RootSchemaType<{
740
+ timeline: import("loro-mirror").LoroMapSchema<{
741
+ unit_time_ms: /*elided*/any;
742
+ }> & {
743
+ options: {};
744
+ } & {
745
+ catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
746
+ unit_time_ms: /*elided*/any;
747
+ }, C>;
748
+ };
749
+ tracks: import("loro-mirror").LoroMovableListSchema<import("loro-mirror").LoroMapSchema<{
750
+ id: /*elided*/any;
751
+ parts_kind: /*elided*/any;
752
+ is_hidden: /*elided*/any;
753
+ items: /*elided*/any;
754
+ }> & {
755
+ options: {};
756
+ } & {
757
+ catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
758
+ id: /*elided*/any;
759
+ parts_kind: /*elided*/any;
760
+ is_hidden: /*elided*/any;
761
+ items: /*elided*/any;
762
+ }, C>;
763
+ }> & {
764
+ options: {};
765
+ };
766
+ part_library: import("loro-mirror").LoroMapSchemaWithCatchall<{}, import("loro-mirror").LoroMapSchema<{
767
+ video_clip: /*elided*/any;
768
+ speech: /*elided*/any;
769
+ caption: /*elided*/any;
770
+ bgm: /*elided*/any;
771
+ }> & {
772
+ options: {};
773
+ } & {
774
+ catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
775
+ video_clip: /*elided*/any;
776
+ speech: /*elided*/any;
777
+ caption: /*elided*/any;
778
+ bgm: /*elided*/any;
779
+ }, C>;
780
+ }> & {
781
+ options: {};
782
+ };
783
+ }> & {
784
+ options: {};
785
+ };
786
+ type VideoDocumentMirrorSchema = typeof videoDocumentMirrorSchema;
787
+ /**
788
+ * The mutable draft an op's `transact` callback edits, inferred from the schema.
789
+ *
790
+ * `InferInputType` is the schema's *input* shape: the declared business fields
791
+ * with the `$cid` container ids (which mirror injects into its output
792
+ * `InferType`) made optional, so ops assign plain objects without supplying
793
+ * `$cid`. Deriving it from the schema keeps draft and storage in lockstep — a
794
+ * schema change is a compile error at every edit site, not a silent drift.
795
+ * Reorders within `items` still diff to real Loro `move` ops because the schema
796
+ * keys items by `part_id`.
797
+ */
798
+ type VideoDocumentDraft = InferInputType<VideoDocumentMirrorSchema>;
799
+ /** Track value as it appears in a draft. Derived from the single `tracks` movable list. */
800
+ type TrackDraft = NonNullable<NonNullable<VideoDocumentDraft['tracks']>[number]>;
801
+ /** A single track item in a draft. */
802
+ type TrackItemDraft = NonNullable<NonNullable<TrackDraft['items']>[number]>;
803
+ //#endregion
804
+ //#region src/timeline-core/bridge.d.ts
805
+ /**
806
+ * Bridge between the authoritative `VideoDocument` (position-only facts) and the
807
+ * flat `TimelineDoc` the cascade primitives solve over.
808
+ *
809
+ * The data flow is single-directional (RFC 02 §7/§10): ops write only facts
810
+ * (`time_position`, parts) to `VideoDocument`; absolute time, `part_aggregations`,
811
+ * total duration, and gap fillers are NOT stored — the projection derives them
812
+ * on read by running the cascade. There is no write-back of solved positions.
813
+ *
814
+ * - `solveVideoDocument` seeds a `TimelineDoc` from each item's `time_position`,
815
+ * runs the full cascade, and returns the derived read-view (abs / aggregations
816
+ * / duration). It is the single solve shared by the legacy `VideoDraft`
817
+ * projection.
818
+ * - `ensureLaneTrack` / `findLaneTrack` locate (or mint) a secondary lane's
819
+ * track row in the draft, so ops can write authoritative facts onto the right
820
+ * named container (lane = container).
821
+ */
822
+ /** The projection-derived read-view of a `VideoDocument` (RFC 02 §7). */
823
+ interface SolvedVideoDocument {
824
+ absByPartId: Map<string, number>;
825
+ aggregations: PartAggregation[];
826
+ durationMs: number;
827
+ partLibrary: Record<string, PartUnion>;
828
+ /**
829
+ * Part ids of the gap fillers this solve minted.
830
+ *
831
+ * They exist only inside the solve: gap filling needs them so the clips after a
832
+ * gap land at the right absolute time, but they are not authoritative state and
833
+ * the read view does not carry them (see `fromVideoDocument`).
834
+ *
835
+ * Reported as ids rather than left for the caller to detect, because the caller
836
+ * *cannot* detect them. The obvious predicate — `origin_media_id === ''` — also
837
+ * matches an empty clip a writer placed on purpose (`batch_replace_video_clip_sequence`
838
+ * documents "Omit to create an empty clip placeholder"), and those are
839
+ * authoritative parts that must survive the projection. The mint callback is the
840
+ * only place that knows the difference.
841
+ *
842
+ * Note this deliberately excludes the fillers that gap filling *extended* rather
843
+ * than minted (`fillMainTrackTimeGaps` cases 1 and 2): those are authoritative
844
+ * empty clips already in `part_library`, and only their length is derived.
845
+ */
846
+ derivedFillerPartIds: Set<string>;
847
+ }
848
+ /** How the caller obtained the document it is asking to be solved. */
849
+ interface SolveVideoDocumentOptions {
850
+ /**
851
+ * The producer already resolved every placement, so the legacy cascade must
852
+ * not run. Only an Entity projection can state this: its placement comes from
853
+ * Clip order / clip-anchor offsets / Marker targetRange, and re-solving would
854
+ * overwrite those and synthesize gap fillers the Entity graph never had.
855
+ *
856
+ * The document itself no longer carries its provenance (P7M14 moved business
857
+ * metadata out of the CRDT), so the caller states it. `hasResolvedPlacement`
858
+ * only verifies the claim — it is never the branch condition, because a
859
+ * legacy draft can satisfy it by accident and a broken projection can fail it.
860
+ */
861
+ readonly placementResolved?: boolean;
862
+ }
863
+ /**
864
+ * Solve a `VideoDocument` (authoritative, position-only) into its derived
865
+ * read-view: absolute time per item, `part_aggregations`, and total duration.
866
+ * This is the read side of the single-directional flow — never written back.
867
+ */
868
+ declare function solveVideoDocument(document: VideoDocument, options?: SolveVideoDocumentOptions): SolvedVideoDocument;
869
+ /** The named container a secondary lane lives in. */
870
+ type SecondaryLane = 'speech' | 'caption' | 'bgm';
871
+ /** A lane's track kind: the `video_clip` main lane plus the three secondary lanes. */
872
+ type LaneKind = SecondaryLane | 'video_clip';
873
+ /**
874
+ * The four lanes in top-to-bottom stack order — the order a `tracks` list holds
875
+ * them in (see {@link laneRank}).
876
+ *
877
+ * Exported so a document can be seeded with all four lanes up front. That seed is
878
+ * not cosmetic: {@link ensureLaneTrack} is find-then-mint over a `LoroMovableList`,
879
+ * so two concurrent writers that each mint the same absent lane both keep their
880
+ * row, and the merged document holds two tracks for one lane. For the main lane
881
+ * that is fatal — `videoDocumentSchema` allows at most one `video_clip` track, so
882
+ * the merged document stops being projectable at all, symmetrically on both
883
+ * replicas. Pre-seeding every lane makes `ensureLaneTrack` always take its find
884
+ * branch, which removes the race by construction rather than by detection.
885
+ *
886
+ * What closes the race is that a track with the lane's `parts_kind` EXISTS — the
887
+ * lookup is by kind, not by id. So a seed is only safe if it covers every lane:
888
+ * a partial seed leaves the uncovered lanes exactly as exposed as before.
889
+ */
890
+ declare const LANE_KINDS_IN_STACK_ORDER: readonly LaneKind[];
891
+ /**
892
+ * The conventional track id for a lane (`main_track`, `<kind>_track`). Shared by
893
+ * the up-front seed and {@link ensureLaneTrack}'s lazy mint so a document's lane
894
+ * ids do not depend on which of the two created the track.
895
+ *
896
+ * Ids are cosmetic to the merge itself — lane lookup goes by `parts_kind`, so
897
+ * drifting them apart would not reopen the concurrent-mint race. They matter to
898
+ * readers that address a lane by id (the FE editor's panes, fixtures), which is
899
+ * why there is one convention rather than two.
900
+ */
901
+ declare function laneTrackId(kind: LaneKind): string;
902
+ /**
903
+ * Locate a lane's track row in the single `tracks` list by kind, minting an empty
904
+ * row in lane-stacking order if absent (reference/17 §4: lane = `parts_kind`).
905
+ * Ops use this to write authoritative items onto the right lane. The track id
906
+ * comes from {@link laneTrackId}, shared with the up-front seed.
907
+ *
908
+ * The mint branch is a concurrency hazard, not a convenience: see
909
+ * {@link LANE_KINDS_IN_STACK_ORDER}. A document seeded with all four lanes never
910
+ * reaches it.
911
+ */
912
+ declare function ensureLaneTrack(draft: VideoDocumentDraft, kind: LaneKind): TrackDraft;
913
+ /** Find a secondary lane's track row without minting it. */
914
+ declare function findLaneTrack(draft: VideoDocumentDraft, kind: SecondaryLane): TrackDraft | undefined;
915
+ //#endregion
727
916
  //#region src/document/projection.d.ts
728
917
  /**
729
- * Projection between the authoritative `VideoDocument` and the legacy
730
- * `VideoDraft` read-view (RFC 02 §5/§7). Both directions live here:
918
+ * Projection between authoritative `VideoDocument` and compatible content
919
+ * layouts (RFC 02 §5/§7). Both directions live here:
731
920
  *
732
921
  * - `toVideoDocument` ingests a `VideoDraft`, deriving each item's `position`
733
922
  * from the legacy absolute layout + aggregations; derived values (abs time,
734
923
  * `part_aggregations`, total duration) are dropped.
735
- * - `fromVideoDocument` solves a `VideoDocument` back into a `VideoDraft` via the
924
+ * - `fromVideoDocument` solves a `VideoDocument` into `VideoDraftContent` via the
736
925
  * timeline-core cascade, re-deriving exactly those values.
737
926
  *
738
927
  * Business validation lives in `validation.ts`; `fromVideoDocument` asserts a
@@ -744,7 +933,7 @@ interface VideoDocumentValidationIssue {
744
933
  * aggregations (RFC 02 §4/§5). Absolute time, `part_aggregations`, and total
745
934
  * duration are dropped — they are re-derived by the projection.
746
935
  */
747
- declare function toVideoDocument(draft: VideoDraft): VideoDocument;
936
+ declare function toVideoDocument(draft: Pick<VideoDraft, keyof VideoDraftContent>): VideoDocument;
748
937
  /** speech/attachment part_id → its host video part_id + relative offset. */
749
938
  type SpeechHostMap = Map<string, {
750
939
  hostPartId: string;
@@ -784,8 +973,8 @@ interface DerivedItemPosition {
784
973
  */
785
974
  declare function derivePositionFromAbs(partId: string, abs: number, isMain: boolean, speechHost: SpeechHostMap, partLibrary: Record<string, PartUnion | string | undefined>): DerivedItemPosition;
786
975
  /**
787
- * Project the authoritative `VideoDocument` back into the legacy `VideoDraft`
788
- * read-view, solving each item's absolute position, the `part_aggregations`, and
976
+ * Project `VideoDocument` into `VideoDraftContent`, solving each item's
977
+ * absolute position, the `part_aggregations`, and
789
978
  * the total duration via the timeline-core cascade.
790
979
  *
791
980
  * The read-view is a compatibility contract, and the IDL declares
@@ -799,32 +988,15 @@ declare function derivePositionFromAbs(partId: string, abs: number, isMain: bool
799
988
  * These two are defaultable because the projection knows their values on its own:
800
989
  * absent `unit_time_ms` means "no display granularity was ever stated" and absent
801
990
  * `is_hidden` means "this track was never hidden". `version` is NOT defaultable
802
- * here — its only honest value is server state (`update_seq`) that a
803
- * `VideoDocument` cannot see, so it stays absent and the HTTP layer fills it.
991
+ * here — it belongs to Director assembly using the server envelope update_seq.
992
+ * Neither business metadata nor a revision counter belongs in content projection.
804
993
  */
805
- declare function fromVideoDocument(document: VideoDocument): VideoDraft;
994
+ declare function fromVideoDocument(document: VideoDocument, options?: SolveVideoDocumentOptions): VideoDraftContent;
806
995
  //#endregion
807
996
  //#region src/document/initial-document.d.ts
808
- /**
809
- * The project facts a freshly created document is built from — exactly the five
810
- * fields Director sets when it creates a draft row, and nothing else.
811
- *
812
- * Deliberately not a whole `VideoDraft`: tracks and the part library of a new
813
- * document are empty by definition, so accepting them would mean accepting
814
- * values that must always be empty, and every such field is a place for a future
815
- * caller to send something that is silently dropped. The narrow shape makes the
816
- * "a new document has no content" rule structural instead of a convention.
817
- */
818
- interface InitialDocumentFacts {
819
- draftId: string;
820
- projectId: string | undefined;
821
- ownerId: string | undefined;
822
- chatSessionId: string | undefined;
823
- videoCreationSettings: VideoCreationSettings | undefined;
824
- }
825
997
  /**
826
998
  * Build the `VideoDocument` a newly created project starts from: the caller's
827
- * project facts, no parts, and one empty track per lane.
999
+ * no parts and one empty track per lane. Business facts remain in Director.
828
1000
  *
829
1001
  * The empty lane tracks are the reason this function exists rather than callers
830
1002
  * assembling a document inline. Lane tracks are otherwise minted lazily by the
@@ -845,7 +1017,7 @@ interface InitialDocumentFacts {
845
1017
  * supplies, and total duration is derived on read (RFC 02 §6), so a new document
846
1018
  * has no timeline fact to state.
847
1019
  */
848
- declare function buildInitialVideoDocument(facts: InitialDocumentFacts): VideoDocument;
1020
+ declare function buildInitialVideoDocument(): VideoDocument;
849
1021
  //#endregion
850
1022
  //#region ../medeo-dsl/src/ids.d.ts
851
1023
  declare const entityIdBrand: unique symbol;
@@ -976,7 +1148,7 @@ declare class EntityTimelineProjectionError extends Error {
976
1148
  * consulted as an editing fact. Peer IDs appear only in this derived read
977
1149
  * contract, reconstructed from relations; they are not stored in payloads.
978
1150
  */
979
- declare function projectEntityTimeline(rows: EntityRelationRows, meta: VideoDocumentMeta): VideoDocument;
1151
+ declare function projectEntityTimeline(rows: EntityRelationRows): VideoDocument;
980
1152
  //#endregion
981
1153
  //#region src/document/entity-timeline-layout.d.ts
982
1154
  type EntityTimelineTrackRole = 'video_clip' | 'speech' | 'caption' | 'bgm';
@@ -1039,95 +1211,6 @@ declare class VideoDocumentValidationError extends Error {
1039
1211
  declare function assertValidVideoDocument(document: unknown): asserts document is VideoDocument;
1040
1212
  declare function validateVideoDocument(document: unknown): VideoDocumentValidationIssue[];
1041
1213
  //#endregion
1042
- //#region src/document/mirror-schema.d.ts
1043
- declare const videoDocumentMirrorSchema: import("loro-mirror").RootSchemaType<{
1044
- meta: import("loro-mirror").LoroMapSchema<{
1045
- schema_version: /*elided*/any;
1046
- draft_id: /*elided*/any;
1047
- project_id: /*elided*/any;
1048
- owner_id: /*elided*/any;
1049
- thumbnail_storage_key: /*elided*/any;
1050
- chat_session_id: /*elided*/any;
1051
- video_creation_settings: /*elided*/any;
1052
- version: /*elided*/any;
1053
- }> & {
1054
- options: {};
1055
- } & {
1056
- catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
1057
- schema_version: /*elided*/any;
1058
- draft_id: /*elided*/any;
1059
- project_id: /*elided*/any;
1060
- owner_id: /*elided*/any;
1061
- thumbnail_storage_key: /*elided*/any;
1062
- chat_session_id: /*elided*/any;
1063
- video_creation_settings: /*elided*/any;
1064
- version: /*elided*/any;
1065
- }, C>;
1066
- };
1067
- timeline: import("loro-mirror").LoroMapSchema<{
1068
- unit_time_ms: /*elided*/any;
1069
- }> & {
1070
- options: {};
1071
- } & {
1072
- catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
1073
- unit_time_ms: /*elided*/any;
1074
- }, C>;
1075
- };
1076
- tracks: import("loro-mirror").LoroMovableListSchema<import("loro-mirror").LoroMapSchema<{
1077
- id: /*elided*/any;
1078
- parts_kind: /*elided*/any;
1079
- is_hidden: /*elided*/any;
1080
- items: /*elided*/any;
1081
- }> & {
1082
- options: {};
1083
- } & {
1084
- catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
1085
- id: /*elided*/any;
1086
- parts_kind: /*elided*/any;
1087
- is_hidden: /*elided*/any;
1088
- items: /*elided*/any;
1089
- }, C>;
1090
- }> & {
1091
- options: {};
1092
- };
1093
- part_library: import("loro-mirror").LoroMapSchemaWithCatchall<{}, import("loro-mirror").LoroMapSchema<{
1094
- video_clip: /*elided*/any;
1095
- speech: /*elided*/any;
1096
- caption: /*elided*/any;
1097
- bgm: /*elided*/any;
1098
- }> & {
1099
- options: {};
1100
- } & {
1101
- catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
1102
- video_clip: /*elided*/any;
1103
- speech: /*elided*/any;
1104
- caption: /*elided*/any;
1105
- bgm: /*elided*/any;
1106
- }, C>;
1107
- }> & {
1108
- options: {};
1109
- };
1110
- }> & {
1111
- options: {};
1112
- };
1113
- type VideoDocumentMirrorSchema = typeof videoDocumentMirrorSchema;
1114
- /**
1115
- * The mutable draft an op's `transact` callback edits, inferred from the schema.
1116
- *
1117
- * `InferInputType` is the schema's *input* shape: the declared business fields
1118
- * with the `$cid` container ids (which mirror injects into its output
1119
- * `InferType`) made optional, so ops assign plain objects without supplying
1120
- * `$cid`. Deriving it from the schema keeps draft and storage in lockstep — a
1121
- * schema change is a compile error at every edit site, not a silent drift.
1122
- * Reorders within `items` still diff to real Loro `move` ops because the schema
1123
- * keys items by `part_id`.
1124
- */
1125
- type VideoDocumentDraft = InferInputType<VideoDocumentMirrorSchema>;
1126
- /** Track value as it appears in a draft. Derived from the single `tracks` movable list. */
1127
- type TrackDraft = NonNullable<NonNullable<VideoDocumentDraft['tracks']>[number]>;
1128
- /** A single track item in a draft. */
1129
- type TrackItemDraft = NonNullable<NonNullable<TrackDraft['items']>[number]>;
1130
- //#endregion
1131
1214
  //#region src/editor/id-gen.d.ts
1132
1215
  /**
1133
1216
  * Part-id generation, aligned with the online ecosystem.
@@ -1350,13 +1433,12 @@ interface TransactAudit {
1350
1433
  * position. The caller never materializes a layout (ADR 0009).
1351
1434
  */
1352
1435
  interface SemanticDocumentAdapter extends SnapshotReadable {
1353
- /** True once the document holds real content (a bootstrapped/synced snapshot). */
1354
- hasContent(): boolean;
1355
1436
  /**
1356
- * Apply one op's whole mutation in a single transaction. `edit` mutates the
1357
- * document draft; the adapter diffs the result and commits once with `audit`.
1437
+ * Apply one op's domain mutation in a single synchronous transaction. `edit`
1438
+ * must finish before returning; async callbacks/await are unsupported. The
1439
+ * adapter diffs the resulting draft and commits once with `audit`.
1358
1440
  * A throw in `edit` rolls back (the draft is discarded, Loro untouched). An
1359
- * edit that changes nothing produces no commit (no phantom audit entry).
1441
+ * edit that changes nothing produces no domain commit (no phantom undo step).
1360
1442
  */
1361
1443
  transact(edit: (draft: VideoDocumentDraft) => void, audit: TransactAudit): void;
1362
1444
  }
@@ -1492,6 +1574,19 @@ declare class SemanticEditor {
1492
1574
  private computeAddInsertIndex;
1493
1575
  }
1494
1576
  //#endregion
1577
+ //#region src/document/document-mutation-guard.d.ts
1578
+ /**
1579
+ * @internal
1580
+ * Shared by synchronous mutation entry points for one document. The session
1581
+ * closes it before teardown callbacks can attempt another write.
1582
+ */
1583
+ declare class DocumentMutationGuard {
1584
+ private running;
1585
+ private closed;
1586
+ run<T>(mutation: () => T): T;
1587
+ close(): void;
1588
+ }
1589
+ //#endregion
1495
1590
  //#region src/document/mirror-adapter.d.ts
1496
1591
  interface MirrorVideoDocumentOptions {
1497
1592
  peerId?: PeerID;
@@ -1507,22 +1602,31 @@ interface MirrorVideoDocumentOptions {
1507
1602
  * - `transact(edit, audit)` runs the whole op in one `mirror.setState` callback:
1508
1603
  * one diff, one `doc.commit` carrying the audit message. The callback edits an
1509
1604
  * immer draft, so a throw inside it discards the draft and never touches Loro
1510
- * (natural rollback) — no `guard` / `rollback` / `openTransaction` machinery.
1605
+ * (natural rollback) without a document checkout or compensating commit.
1511
1606
  * - mirror's `idSelector` (track items keyed by `part_id`) diffs reorders to
1512
1607
  * real Loro `move` ops on every lane, so per-item CRDT identity survives on
1513
1608
  * main and secondary tracks alike.
1514
1609
  */
1515
1610
  declare class MirrorVideoDocumentAdapter implements SemanticDocumentAdapter {
1516
1611
  readonly doc: LoroDoc;
1612
+ private readonly mutationGuard;
1517
1613
  private readonly mirror;
1518
- constructor(doc: LoroDoc);
1614
+ private disposed;
1615
+ constructor(doc: LoroDoc, mutationGuard?: DocumentMutationGuard);
1519
1616
  snapshot(): VideoDocument;
1520
1617
  /**
1521
- * True once the doc holds real document content. A fresh mirror over an empty
1522
- * doc still reports defaulted root maps, so probe the stored `schema_version`
1523
- * (empty until a snapshot is bootstrapped or synced in).
1618
+ * Native Entity authority: placement is already solved by the Entity graph.
1619
+ *
1620
+ * The root check goes through `getShallowValue` first because `getMap` creates
1621
+ * the container on access — probing a legacy document for `medeo` would
1622
+ * otherwise mutate it, which a read must never do.
1524
1623
  */
1525
- hasContent(): boolean;
1624
+ isEntityDocument(): boolean;
1625
+ /**
1626
+ * Release mirror subscriptions; do not reuse this adapter afterwards.
1627
+ * The caller still owns the borrowed LoroDoc.
1628
+ */
1629
+ dispose(): void;
1526
1630
  /**
1527
1631
  * Apply one op as a single transaction. `edit` mutates the immer draft; mirror
1528
1632
  * diffs the result and commits once with the audit `message`. A throw in `edit`
@@ -1530,15 +1634,12 @@ declare class MirrorVideoDocumentAdapter implements SemanticDocumentAdapter {
1530
1634
  * skips the commit — matching the prior "empty op leaves no audit" behavior.
1531
1635
  */
1532
1636
  transact(edit: (draft: VideoDocumentDraft) => void, audit: TransactAudit): void;
1637
+ private assertActive;
1533
1638
  }
1534
1639
  /** Build a fresh Loro doc seeded with `document` through the mirror. */
1535
1640
  declare function createMirrorVideoDocument(document: VideoDocument, options?: MirrorVideoDocumentOptions): LoroDoc;
1536
1641
  /** Build a `MirrorVideoDocumentAdapter` over a fresh doc seeded with `document`. */
1537
1642
  declare function createMirrorVideoDocumentAdapter(document: VideoDocument, options?: MirrorVideoDocumentOptions): MirrorVideoDocumentAdapter;
1538
- /** Host-only replacement of a derived view, retaining the existing Loro history. */
1539
- declare function applyEntityTimelineProjection(doc: LoroDoc, projection: VideoDocument, entityRevision: number): Uint8Array;
1540
- /** Write a whole `VideoDocument` into a draft (seed a fresh doc / plain-memory state). */
1541
- declare function writeVideoDocumentToDraft(draft: VideoDocumentDraft, document: VideoDocument): void;
1542
1643
  //#endregion
1543
1644
  //#region src/document/plain-memory-adapter.d.ts
1544
1645
  /**
@@ -1552,6 +1653,12 @@ interface JournalEntry extends TransactAudit {
1552
1653
  interface PlainMemoryAdapterOptions {
1553
1654
  /** Underlying id mint; wrapped so each call inside a transact is journaled. */
1554
1655
  idFactory?: PartIdFactory;
1656
+ /**
1657
+ * Refuse every `transact`. Set when the seed document is an Entity projection:
1658
+ * its timeline is owned by the Entity graph, and the document itself no longer
1659
+ * states its provenance (business metadata left the CRDT), so the caller does.
1660
+ */
1661
+ readOnly?: boolean;
1555
1662
  }
1556
1663
  /**
1557
1664
  * Pure in-memory `SemanticDocumentAdapter` — no Loro/WASM. Holds a
@@ -1575,6 +1682,7 @@ declare class PlainMemoryAdapter implements SemanticDocumentAdapter {
1575
1682
  * use this so every minted id is appended to the current transact's list.
1576
1683
  */
1577
1684
  readonly idFactory: PartIdFactory;
1685
+ private readonly readOnly;
1578
1686
  constructor(document: VideoDocument, options?: PlainMemoryAdapterOptions);
1579
1687
  get journal(): readonly JournalEntry[];
1580
1688
  hasContent(): boolean;
@@ -1593,9 +1701,9 @@ declare function createPlainMemoryAdapter(document: VideoDocument, options?: Pla
1593
1701
  /**
1594
1702
  * Project the mirror state (`VideoDocumentDraft`) into the authoritative
1595
1703
  * `VideoDocument`. The storage shape is isomorphic to the domain shape (RFC 03
1596
- * §4, reference/17 §4: meta map + a single `tracks` list + part_library), so this
1704
+ * §4, reference/17 §4: timeline + a single `tracks` list + part_library), so this
1597
1705
  * is a near-identity — it reads `time_position` / `fallback_abs_ms` JSON blobs
1598
- * back into structured values and trims empty strings, nothing more.
1706
+ * back into structured values and selects content fields. Legacy meta is ignored.
1599
1707
  *
1600
1708
  * It maps only authoritative facts (RFC 02 §6): `part_id` + `time_position`. The
1601
1709
  * projection-derived `VideoDraft` read-view (absolute time, `part_aggregations`,
@@ -1671,19 +1779,6 @@ declare const partUnionSchema: z.ZodUnion<readonly [z.ZodObject<{
1671
1779
  }, z.core.$loose>;
1672
1780
  }, z.core.$loose>]>;
1673
1781
  declare const videoDocumentSchema: z.ZodObject<{
1674
- meta: z.ZodObject<{
1675
- schema_version: z.ZodEnum<{
1676
- "video-document/v0": "video-document/v0";
1677
- "video-document/entity-projection-v1": "video-document/entity-projection-v1";
1678
- }>;
1679
- draft_id: z.ZodOptional<z.ZodString>;
1680
- project_id: z.ZodOptional<z.ZodString>;
1681
- owner_id: z.ZodOptional<z.ZodString>;
1682
- thumbnail_storage_key: z.ZodOptional<z.ZodString>;
1683
- chat_session_id: z.ZodOptional<z.ZodString>;
1684
- video_creation_settings: z.ZodOptional<z.ZodUnknown>;
1685
- version: z.ZodOptional<z.ZodNumber>;
1686
- }, z.core.$loose>;
1687
1782
  timeline: z.ZodOptional<z.ZodObject<{
1688
1783
  unit_time_ms: z.ZodOptional<z.ZodNumber>;
1689
1784
  }, z.core.$loose>>;
@@ -1775,4 +1870,4 @@ declare const videoDocumentSchema: z.ZodObject<{
1775
1870
  }, z.core.$loose>]>>>;
1776
1871
  }, z.core.$loose>;
1777
1872
  //#endregion
1778
- export { SequenceRange as $, generatePartId as A, VideoDraft as At, ResolvedEntityClipPlacement as B, Track$1 as Bt, PlannedSemanticOpKind as C, TrackItemTimePosition as Ct, SnapshotReadable as D, VideoDocumentSchemaVersion as Dt, SchemaValidator as E, VideoDocument as Et, videoDocumentMirrorSchema as F, CaptionPart$1 as Ft, EntityTimelineProjectionError as G, ResolvedEntityTrack as H, VideoDocumentValidationError as I, CaptionStyle as It, RelationRow as J, EntityRelationRows as K, assertValidVideoDocument as L, PartAggregation as Lt, TrackItemDraft as M, effectiveVideoClipDurationMs as Mt, VideoDocumentDraft as N, speedOf as Nt, ValidationError as O, VideoDocumentValidationIssue as Ot, VideoDocumentMirrorSchema as P, Attachment as Pt, SequenceDuration as Q, validateVideoDocument as R, SpeedShift as Rt, ImplementedSemanticOpKind as S, TrackItem as St, isImplementedSemanticOpKind as T, VideoClipPart as Tt, resolveEntityTimelineLayout as U, ResolvedEntityTimelineLayout as V, TrackItem$1 as Vt, projectEntityTimeline as W, CaptionStyleFields as X, CaptionSegmentSelection as Y, ScriptTextSegment as Z, SemanticEditor as _, PartKind as _t, PlainMemoryAdapter as a, buildInitialVideoDocument as at, TransactAudit as b, Timeline as bt, MirrorVideoDocumentAdapter as c, buildSpeechHostMap as ct, createMirrorVideoDocument as d, toVideoDocument as dt, VoiceDescriptor as et, createMirrorVideoDocumentAdapter as f, BgmPart as ft, SemanticDocumentAdapter as g, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION as gt, OpActor as h, DEFAULT_UNIT_TIME_MS as ht, JournalEntry as i, InitialDocumentFacts as it, TrackDraft as j, VideoDraftPartUnion as jt, PartIdFactory as k, VideoDocumentValidationIssueCode as kt, MirrorVideoDocumentOptions as l, derivePositionFromAbs as lt, CommitOptions as m, CaptionPart as mt, videoDocumentSchema as n, JsonValue as nt, PlainMemoryAdapterOptions as o, DerivedItemPosition as ot, writeVideoDocumentToDraft as p, CaptionDisplayCue as pt, EntityRow as q, readVideoDocumentFromDraft as r, EntityId as rt, createPlainMemoryAdapter as s, SpeechHostMap as st, partUnionSchema as t, JsonObject as tt, applyEntityTimelineProjection as u, fromVideoDocument as ut, SemanticOpInput as v, PartUnion as vt, SemanticOpKind as w, VIDEO_DOCUMENT_SCHEMA_VERSION as wt, IMPLEMENTED_SEMANTIC_OP_KINDS as x, Track as xt, SemanticOpName as y, SpeechPart as yt, EntityTimelineTrackRole as z, Timeline$1 as zt };
1873
+ export { SpeechHostMap as $, assertValidVideoDocument as A, VideoDocumentValidationIssueCode as At, EntityRow as B, SpeedShift as Bt, isImplementedSemanticOpKind as C, Timeline as Ct, PartIdFactory as D, VideoClipPart as Dt, ValidationError as E, TrackItemTimePosition as Et, ResolvedEntityTrack as F, speedOf as Ft, SequenceDuration as G, CaptionSegmentSelection as H, Track$1 as Ht, resolveEntityTimelineLayout as I, Attachment as It, JsonObject as J, SequenceRange as K, projectEntityTimeline as L, CaptionPart$1 as Lt, EntityTimelineTrackRole as M, VideoDraftContent as Mt, ResolvedEntityClipPlacement as N, VideoDraftPartUnion as Nt, generatePartId as O, VideoDocument as Ot, ResolvedEntityTimelineLayout as P, effectiveVideoClipDurationMs as Pt, DerivedItemPosition as Q, EntityTimelineProjectionError as R, CaptionStyle as Rt, SemanticOpKind as S, SpeechPart as St, SnapshotReadable as T, TrackItem as Tt, CaptionStyleFields as U, TrackItem$1 as Ut, RelationRow as V, Timeline$1 as Vt, ScriptTextSegment as W, EntityId as X, JsonValue as Y, buildInitialVideoDocument as Z, SemanticOpName as _, CaptionDisplayCue as _t, PlainMemoryAdapter as a, LaneKind as at, ImplementedSemanticOpKind as b, PartKind as bt, MirrorVideoDocumentAdapter as c, findLaneTrack as ct, createMirrorVideoDocumentAdapter as d, TrackDraft as dt, buildSpeechHostMap as et, CommitOptions as f, TrackItemDraft as ft, SemanticOpInput as g, BgmPart as gt, SemanticEditor as h, videoDocumentMirrorSchema as ht, JournalEntry as i, LANE_KINDS_IN_STACK_ORDER as it, validateVideoDocument as j, VideoDraft as jt, VideoDocumentValidationError as k, VideoDocumentValidationIssue as kt, MirrorVideoDocumentOptions as l, laneTrackId as lt, SemanticDocumentAdapter as m, VideoDocumentMirrorSchema as mt, videoDocumentSchema as n, fromVideoDocument as nt, PlainMemoryAdapterOptions as o, SolvedVideoDocument as ot, OpActor as p, VideoDocumentDraft as pt, VoiceDescriptor as q, readVideoDocumentFromDraft as r, toVideoDocument as rt, createPlainMemoryAdapter as s, ensureLaneTrack as st, partUnionSchema as t, derivePositionFromAbs as tt, createMirrorVideoDocument as u, solveVideoDocument as ut, TransactAudit as v, CaptionPart as vt, SchemaValidator as w, Track as wt, PlannedSemanticOpKind as x, PartUnion as xt, IMPLEMENTED_SEMANTIC_OP_KINDS as y, DEFAULT_UNIT_TIME_MS as yt, EntityRelationRows as z, PartAggregation as zt };