@mengine/medeo-client 2.0.1-alpha.2 → 2.0.1-alpha.21

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
@@ -477,6 +473,8 @@ type VideoClipPart = Omit<VideoClipPart$1, 'duration_ms'>;
477
473
  type SpeechPart = Omit<SpeechPart$1, 'duration_ms'> & {
478
474
  media_duration_ms?: number | undefined;
479
475
  };
476
+ /** Asset namespace exposed only by the legacy read view; never an authoritative Speech fact. */
477
+ type SpeechOriginAssetSystem = 'memota' | 'memota-speech';
480
478
  /**
481
479
  * Authoritative caption part. The IDL `CaptionPart` carries `duration_ms` (the
482
480
  * effective display length, a derived read-view value); the authoritative store
@@ -625,7 +623,8 @@ type VideoDraftPartUnion = {
625
623
  } | {
626
624
  video_clip?: never;
627
625
  speech: SpeechPart & {
628
- duration_ms?: number;
626
+ duration_ms?: number; /** Absent only on historical drafts created before this read-view discriminator. */
627
+ origin_asset_system?: SpeechOriginAssetSystem;
629
628
  };
630
629
  caption?: never;
631
630
  bgm?: never;
@@ -645,17 +644,53 @@ type VideoDraftPartUnion = {
645
644
  };
646
645
  };
647
646
  /**
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).
647
+ * Legacy Draft import shape. It allows omitted durations and engine extensions
648
+ * so existing fixtures and migrations can state only the facts they have.
649
+ * Projection returns the narrower `VideoDraftContent` contract instead.
654
650
  */
655
651
  type VideoDraft = Omit<VideoDraft$1, 'part_library' | 'video_creation_settings'> & {
656
652
  part_library: Record<string, VideoDraftPartUnion> | undefined;
657
653
  video_creation_settings?: VideoCreationSettings | undefined;
658
654
  };
655
+ /**
656
+ * The complete content read model produced by the shared projection. Business
657
+ * identity, settings, thumbnail and revision counters are assembled by Director;
658
+ * keeping an explicit field list prevents new business DTO fields entering here.
659
+ */
660
+ type VideoDraftContent = Pick<VideoDraft, 'timeline' | 'main_track' | 'above_main_tracks' | 'below_main_tracks' | 'part_aggregations'> & {
661
+ part_library: Record<string, VideoDraftContentPartUnion> | undefined;
662
+ };
663
+ /** Projection always states the duration field; legacy imports may omit it. */
664
+ type VideoDraftContentPartUnion = {
665
+ video_clip: VideoClipPart & {
666
+ duration_ms: number | undefined;
667
+ };
668
+ speech?: never;
669
+ caption?: never;
670
+ bgm?: never;
671
+ } | {
672
+ video_clip?: never;
673
+ speech: SpeechPart & {
674
+ duration_ms: number | undefined;
675
+ origin_asset_system?: SpeechOriginAssetSystem;
676
+ };
677
+ caption?: never;
678
+ bgm?: never;
679
+ } | {
680
+ video_clip?: never;
681
+ speech?: never;
682
+ caption: CaptionPart & {
683
+ duration_ms: number | undefined;
684
+ };
685
+ bgm?: never;
686
+ } | {
687
+ video_clip?: never;
688
+ speech?: never;
689
+ caption?: never;
690
+ bgm: BgmPart & {
691
+ duration_ms: number | undefined;
692
+ };
693
+ };
659
694
  /** Authoritative timeline: `duration_ms` is derived (= longest track), not stored. */
660
695
  interface Timeline {
661
696
  unit_time_ms: number | undefined;
@@ -670,39 +705,19 @@ interface Timeline {
670
705
  * is not, and passes any `>= 0` guard on its way to an editor that cannot use it.
671
706
  */
672
707
  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
708
  /**
693
709
  * Authoritative collaborative document: only facts. Positioning lives on each
694
710
  * `TrackItem.time_position`; absolute time, `part_aggregations`, and total
695
711
  * duration are derived in the `VideoDraft` projection, not stored here (RFC 02 §6).
696
712
  *
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
713
+ * The content mirrors Loro storage: timeline, part library, and a single
714
+ * ordered `tracks` list (reference/17 §4). Business metadata stays in Director. A
699
715
  * track's lane is expressed by its `parts_kind`, not by which container it lives
700
716
  * in — the `main` / `above` / `below` three-pane view is reconstructed at
701
717
  * projection time. Order is the list order itself, so there is no `lane` /
702
718
  * `lane_order` field to diverge under concurrent edits.
703
719
  */
704
720
  interface VideoDocument {
705
- meta: VideoDocumentMeta;
706
721
  timeline: Timeline | undefined;
707
722
  tracks: Track[] | undefined;
708
723
  part_library: Record<string, PartUnion> | undefined;
@@ -724,15 +739,193 @@ interface VideoDocumentValidationIssue {
724
739
  severity?: VideoDocumentValidationIssueSeverity;
725
740
  }
726
741
  //#endregion
742
+ //#region src/document/mirror-schema.d.ts
743
+ declare const videoDocumentMirrorSchema: import("loro-mirror").RootSchemaType<{
744
+ timeline: import("loro-mirror").LoroMapSchema<{
745
+ unit_time_ms: /*elided*/any;
746
+ }> & {
747
+ options: {};
748
+ } & {
749
+ catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
750
+ unit_time_ms: /*elided*/any;
751
+ }, C>;
752
+ };
753
+ tracks: import("loro-mirror").LoroMovableListSchema<import("loro-mirror").LoroMapSchema<{
754
+ id: /*elided*/any;
755
+ parts_kind: /*elided*/any;
756
+ is_hidden: /*elided*/any;
757
+ items: /*elided*/any;
758
+ }> & {
759
+ options: {};
760
+ } & {
761
+ catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
762
+ id: /*elided*/any;
763
+ parts_kind: /*elided*/any;
764
+ is_hidden: /*elided*/any;
765
+ items: /*elided*/any;
766
+ }, C>;
767
+ }> & {
768
+ options: {};
769
+ };
770
+ part_library: import("loro-mirror").LoroMapSchemaWithCatchall<{}, import("loro-mirror").LoroMapSchema<{
771
+ video_clip: /*elided*/any;
772
+ speech: /*elided*/any;
773
+ caption: /*elided*/any;
774
+ bgm: /*elided*/any;
775
+ }> & {
776
+ options: {};
777
+ } & {
778
+ catchall: <C extends import("loro-mirror").SchemaType>(catchallSchema: C) => import("loro-mirror").LoroMapSchemaWithCatchall<{
779
+ video_clip: /*elided*/any;
780
+ speech: /*elided*/any;
781
+ caption: /*elided*/any;
782
+ bgm: /*elided*/any;
783
+ }, C>;
784
+ }> & {
785
+ options: {};
786
+ };
787
+ }> & {
788
+ options: {};
789
+ };
790
+ type VideoDocumentMirrorSchema = typeof videoDocumentMirrorSchema;
791
+ /**
792
+ * The mutable draft an op's `transact` callback edits, inferred from the schema.
793
+ *
794
+ * `InferInputType` is the schema's *input* shape: the declared business fields
795
+ * with the `$cid` container ids (which mirror injects into its output
796
+ * `InferType`) made optional, so ops assign plain objects without supplying
797
+ * `$cid`. Deriving it from the schema keeps draft and storage in lockstep — a
798
+ * schema change is a compile error at every edit site, not a silent drift.
799
+ * Reorders within `items` still diff to real Loro `move` ops because the schema
800
+ * keys items by `part_id`.
801
+ */
802
+ type VideoDocumentDraft = InferInputType<VideoDocumentMirrorSchema>;
803
+ /** Track value as it appears in a draft. Derived from the single `tracks` movable list. */
804
+ type TrackDraft = NonNullable<NonNullable<VideoDocumentDraft['tracks']>[number]>;
805
+ /** A single track item in a draft. */
806
+ type TrackItemDraft = NonNullable<NonNullable<TrackDraft['items']>[number]>;
807
+ //#endregion
808
+ //#region src/timeline-core/bridge.d.ts
809
+ /**
810
+ * Bridge between the authoritative `VideoDocument` (position-only facts) and the
811
+ * flat `TimelineDoc` the cascade primitives solve over.
812
+ *
813
+ * The data flow is single-directional (RFC 02 §7/§10): ops write only facts
814
+ * (`time_position`, parts) to `VideoDocument`; absolute time, `part_aggregations`,
815
+ * total duration, and gap fillers are NOT stored — the projection derives them
816
+ * on read by running the cascade. There is no write-back of solved positions.
817
+ *
818
+ * - `solveVideoDocument` seeds a `TimelineDoc` from each item's `time_position`,
819
+ * runs the full cascade, and returns the derived read-view (abs / aggregations
820
+ * / duration). It is the single solve shared by the legacy `VideoDraft`
821
+ * projection.
822
+ * - `ensureLaneTrack` / `findLaneTrack` locate (or mint) a secondary lane's
823
+ * track row in the draft, so ops can write authoritative facts onto the right
824
+ * named container (lane = container).
825
+ */
826
+ /** The projection-derived read-view of a `VideoDocument` (RFC 02 §7). */
827
+ interface SolvedVideoDocument {
828
+ absByPartId: Map<string, number>;
829
+ aggregations: PartAggregation[];
830
+ durationMs: number;
831
+ partLibrary: Record<string, PartUnion>;
832
+ /**
833
+ * Part ids of the gap fillers this solve minted.
834
+ *
835
+ * They exist only inside the solve: gap filling needs them so the clips after a
836
+ * gap land at the right absolute time, but they are not authoritative state and
837
+ * the read view does not carry them (see `fromVideoDocument`).
838
+ *
839
+ * Reported as ids rather than left for the caller to detect, because the caller
840
+ * *cannot* detect them. The obvious predicate — `origin_media_id === ''` — also
841
+ * matches an empty clip a writer placed on purpose (`batch_replace_video_clip_sequence`
842
+ * documents "Omit to create an empty clip placeholder"), and those are
843
+ * authoritative parts that must survive the projection. The mint callback is the
844
+ * only place that knows the difference.
845
+ *
846
+ * Note this deliberately excludes the fillers that gap filling *extended* rather
847
+ * than minted (`fillMainTrackTimeGaps` cases 1 and 2): those are authoritative
848
+ * empty clips already in `part_library`, and only their length is derived.
849
+ */
850
+ derivedFillerPartIds: Set<string>;
851
+ }
852
+ /** How the caller obtained the document it is asking to be solved. */
853
+ interface SolveVideoDocumentOptions {
854
+ /**
855
+ * The producer already resolved every placement, so the legacy cascade must
856
+ * not run. Only an Entity projection can state this: its placement comes from
857
+ * Clip order / clip-anchor offsets / Marker targetRange, and re-solving would
858
+ * overwrite those and synthesize gap fillers the Entity graph never had.
859
+ *
860
+ * The document itself no longer carries its provenance (P7M14 moved business
861
+ * metadata out of the CRDT), so the caller states it. `hasResolvedPlacement`
862
+ * only verifies the claim — it is never the branch condition, because a
863
+ * legacy draft can satisfy it by accident and a broken projection can fail it.
864
+ */
865
+ readonly placementResolved?: boolean;
866
+ }
867
+ /**
868
+ * Solve a `VideoDocument` (authoritative, position-only) into its derived
869
+ * read-view: absolute time per item, `part_aggregations`, and total duration.
870
+ * This is the read side of the single-directional flow — never written back.
871
+ */
872
+ declare function solveVideoDocument(document: VideoDocument, options?: SolveVideoDocumentOptions): SolvedVideoDocument;
873
+ /** The named container a secondary lane lives in. */
874
+ type SecondaryLane = 'speech' | 'caption' | 'bgm';
875
+ /** A lane's track kind: the `video_clip` main lane plus the three secondary lanes. */
876
+ type LaneKind = SecondaryLane | 'video_clip';
877
+ /**
878
+ * The four lanes in top-to-bottom stack order — the order a `tracks` list holds
879
+ * them in (see {@link laneRank}).
880
+ *
881
+ * Exported so a document can be seeded with all four lanes up front. That seed is
882
+ * not cosmetic: {@link ensureLaneTrack} is find-then-mint over a `LoroMovableList`,
883
+ * so two concurrent writers that each mint the same absent lane both keep their
884
+ * row, and the merged document holds two tracks for one lane. For the main lane
885
+ * that is fatal — `videoDocumentSchema` allows at most one `video_clip` track, so
886
+ * the merged document stops being projectable at all, symmetrically on both
887
+ * replicas. Pre-seeding every lane makes `ensureLaneTrack` always take its find
888
+ * branch, which removes the race by construction rather than by detection.
889
+ *
890
+ * What closes the race is that a track with the lane's `parts_kind` EXISTS — the
891
+ * lookup is by kind, not by id. So a seed is only safe if it covers every lane:
892
+ * a partial seed leaves the uncovered lanes exactly as exposed as before.
893
+ */
894
+ declare const LANE_KINDS_IN_STACK_ORDER: readonly LaneKind[];
895
+ /**
896
+ * The conventional track id for a lane (`main_track`, `<kind>_track`). Shared by
897
+ * the up-front seed and {@link ensureLaneTrack}'s lazy mint so a document's lane
898
+ * ids do not depend on which of the two created the track.
899
+ *
900
+ * Ids are cosmetic to the merge itself — lane lookup goes by `parts_kind`, so
901
+ * drifting them apart would not reopen the concurrent-mint race. They matter to
902
+ * readers that address a lane by id (the FE editor's panes, fixtures), which is
903
+ * why there is one convention rather than two.
904
+ */
905
+ declare function laneTrackId(kind: LaneKind): string;
906
+ /**
907
+ * Locate a lane's track row in the single `tracks` list by kind, minting an empty
908
+ * row in lane-stacking order if absent (reference/17 §4: lane = `parts_kind`).
909
+ * Ops use this to write authoritative items onto the right lane. The track id
910
+ * comes from {@link laneTrackId}, shared with the up-front seed.
911
+ *
912
+ * The mint branch is a concurrency hazard, not a convenience: see
913
+ * {@link LANE_KINDS_IN_STACK_ORDER}. A document seeded with all four lanes never
914
+ * reaches it.
915
+ */
916
+ declare function ensureLaneTrack(draft: VideoDocumentDraft, kind: LaneKind): TrackDraft;
917
+ /** Find a secondary lane's track row without minting it. */
918
+ declare function findLaneTrack(draft: VideoDocumentDraft, kind: SecondaryLane): TrackDraft | undefined;
919
+ //#endregion
727
920
  //#region src/document/projection.d.ts
728
921
  /**
729
- * Projection between the authoritative `VideoDocument` and the legacy
730
- * `VideoDraft` read-view (RFC 02 §5/§7). Both directions live here:
922
+ * Projection between authoritative `VideoDocument` and compatible content
923
+ * layouts (RFC 02 §5/§7). Both directions live here:
731
924
  *
732
925
  * - `toVideoDocument` ingests a `VideoDraft`, deriving each item's `position`
733
926
  * from the legacy absolute layout + aggregations; derived values (abs time,
734
927
  * `part_aggregations`, total duration) are dropped.
735
- * - `fromVideoDocument` solves a `VideoDocument` back into a `VideoDraft` via the
928
+ * - `fromVideoDocument` solves a `VideoDocument` into `VideoDraftContent` via the
736
929
  * timeline-core cascade, re-deriving exactly those values.
737
930
  *
738
931
  * Business validation lives in `validation.ts`; `fromVideoDocument` asserts a
@@ -744,7 +937,7 @@ interface VideoDocumentValidationIssue {
744
937
  * aggregations (RFC 02 §4/§5). Absolute time, `part_aggregations`, and total
745
938
  * duration are dropped — they are re-derived by the projection.
746
939
  */
747
- declare function toVideoDocument(draft: VideoDraft): VideoDocument;
940
+ declare function toVideoDocument(draft: Pick<VideoDraft, keyof VideoDraftContent>): VideoDocument;
748
941
  /** speech/attachment part_id → its host video part_id + relative offset. */
749
942
  type SpeechHostMap = Map<string, {
750
943
  hostPartId: string;
@@ -784,8 +977,8 @@ interface DerivedItemPosition {
784
977
  */
785
978
  declare function derivePositionFromAbs(partId: string, abs: number, isMain: boolean, speechHost: SpeechHostMap, partLibrary: Record<string, PartUnion | string | undefined>): DerivedItemPosition;
786
979
  /**
787
- * Project the authoritative `VideoDocument` back into the legacy `VideoDraft`
788
- * read-view, solving each item's absolute position, the `part_aggregations`, and
980
+ * Project `VideoDocument` into `VideoDraftContent`, solving each item's
981
+ * absolute position, the `part_aggregations`, and
789
982
  * the total duration via the timeline-core cascade.
790
983
  *
791
984
  * The read-view is a compatibility contract, and the IDL declares
@@ -799,32 +992,15 @@ declare function derivePositionFromAbs(partId: string, abs: number, isMain: bool
799
992
  * These two are defaultable because the projection knows their values on its own:
800
993
  * absent `unit_time_ms` means "no display granularity was ever stated" and absent
801
994
  * `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.
995
+ * here — it belongs to Director assembly using the server envelope update_seq.
996
+ * Neither business metadata nor a revision counter belongs in content projection.
804
997
  */
805
- declare function fromVideoDocument(document: VideoDocument): VideoDraft;
998
+ declare function fromVideoDocument(document: VideoDocument, options?: SolveVideoDocumentOptions): VideoDraftContent;
806
999
  //#endregion
807
1000
  //#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
1001
  /**
826
1002
  * Build the `VideoDocument` a newly created project starts from: the caller's
827
- * project facts, no parts, and one empty track per lane.
1003
+ * no parts and one empty track per lane. Business facts remain in Director.
828
1004
  *
829
1005
  * The empty lane tracks are the reason this function exists rather than callers
830
1006
  * assembling a document inline. Lane tracks are otherwise minted lazily by the
@@ -845,7 +1021,7 @@ interface InitialDocumentFacts {
845
1021
  * supplies, and total duration is derived on read (RFC 02 §6), so a new document
846
1022
  * has no timeline fact to state.
847
1023
  */
848
- declare function buildInitialVideoDocument(facts: InitialDocumentFacts): VideoDocument;
1024
+ declare function buildInitialVideoDocument(): VideoDocument;
849
1025
  //#endregion
850
1026
  //#region ../medeo-dsl/src/ids.d.ts
851
1027
  declare const entityIdBrand: unique symbol;
@@ -865,7 +1041,7 @@ type JsonObject = {
865
1041
  };
866
1042
  //#endregion
867
1043
  //#region ../medeo-dsl/src/entities.d.ts
868
- type KnownEntityKind = 'axvideo' | 'timeline' | 'track' | 'clip' | 'asset' | 'video' | 'audio' | 'voice' | 'image' | 'sequence-marker' | 'viewport' | 'audio-script' | 'phonetic-script' | 'caption';
1044
+ type KnownEntityKind = 'axvideo' | 'timeline' | 'track' | 'clip' | 'asset' | 'video' | 'audio' | 'voiceover' | 'voice' | 'image' | 'sequence-marker' | 'viewport' | 'audio-script' | 'phonetic-script' | 'caption';
869
1045
  declare const extensionEntityKindBrand: unique symbol;
870
1046
  type ExtensionEntityKind = string & {
871
1047
  readonly [extensionEntityKindBrand]: 'ExtensionEntityKind';
@@ -932,7 +1108,7 @@ type CaptionSegmentSelection = JsonObject & {
932
1108
  };
933
1109
  //#endregion
934
1110
  //#region ../medeo-dsl/src/relations.d.ts
935
- type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'physical-asset' | 'generated' | 'caption-alignment' | 'clip-anchor' | 'phonetic-script-render' | 'audio-script-source' | 'audio-script-marker';
1111
+ type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'from-asset' | 'to-asset' | 'generated' | 'caption-alignment' | 'clip-anchor' | 'phonetic-script-render' | 'audio-script-source' | 'audio-script-marker';
936
1112
  type RelationKind = KnownRelationKind | (string & {});
937
1113
  type RelationTrace = JsonObject;
938
1114
  /**
@@ -971,12 +1147,26 @@ declare class EntityTimelineProjectionError extends Error {
971
1147
  }
972
1148
  //#endregion
973
1149
  //#region src/document/entity-projection.d.ts
1150
+ type EntityTimelineProjectionPart = Exclude<PartUnion, {
1151
+ speech: SpeechPart;
1152
+ }> | {
1153
+ video_clip?: never;
1154
+ speech: SpeechPart & {
1155
+ origin_asset_system: SpeechOriginAssetSystem;
1156
+ };
1157
+ caption?: never;
1158
+ bgm?: never;
1159
+ };
1160
+ /** Ephemeral compatibility document; the origin discriminator is never stored in Loro. */
1161
+ type EntityTimelineProjectionDocument = Omit<VideoDocument, 'part_library'> & {
1162
+ part_library: Record<string, EntityTimelineProjectionPart>;
1163
+ };
974
1164
  /**
975
1165
  * One-way compatibility view over the Entity graph. A legacy part is never
976
1166
  * consulted as an editing fact. Peer IDs appear only in this derived read
977
1167
  * contract, reconstructed from relations; they are not stored in payloads.
978
1168
  */
979
- declare function projectEntityTimeline(rows: EntityRelationRows, meta: VideoDocumentMeta): VideoDocument;
1169
+ declare function projectEntityTimeline(rows: EntityRelationRows): EntityTimelineProjectionDocument;
980
1170
  //#endregion
981
1171
  //#region src/document/entity-timeline-layout.d.ts
982
1172
  type EntityTimelineTrackRole = 'video_clip' | 'speech' | 'caption' | 'bgm';
@@ -1039,95 +1229,6 @@ declare class VideoDocumentValidationError extends Error {
1039
1229
  declare function assertValidVideoDocument(document: unknown): asserts document is VideoDocument;
1040
1230
  declare function validateVideoDocument(document: unknown): VideoDocumentValidationIssue[];
1041
1231
  //#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
1232
  //#region src/editor/id-gen.d.ts
1132
1233
  /**
1133
1234
  * Part-id generation, aligned with the online ecosystem.
@@ -1350,13 +1451,12 @@ interface TransactAudit {
1350
1451
  * position. The caller never materializes a layout (ADR 0009).
1351
1452
  */
1352
1453
  interface SemanticDocumentAdapter extends SnapshotReadable {
1353
- /** True once the document holds real content (a bootstrapped/synced snapshot). */
1354
- hasContent(): boolean;
1355
1454
  /**
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`.
1455
+ * Apply one op's domain mutation in a single synchronous transaction. `edit`
1456
+ * must finish before returning; async callbacks/await are unsupported. The
1457
+ * adapter diffs the resulting draft and commits once with `audit`.
1358
1458
  * 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).
1459
+ * edit that changes nothing produces no domain commit (no phantom undo step).
1360
1460
  */
1361
1461
  transact(edit: (draft: VideoDocumentDraft) => void, audit: TransactAudit): void;
1362
1462
  }
@@ -1492,6 +1592,19 @@ declare class SemanticEditor {
1492
1592
  private computeAddInsertIndex;
1493
1593
  }
1494
1594
  //#endregion
1595
+ //#region src/document/document-mutation-guard.d.ts
1596
+ /**
1597
+ * @internal
1598
+ * Shared by synchronous mutation entry points for one document. The session
1599
+ * closes it before teardown callbacks can attempt another write.
1600
+ */
1601
+ declare class DocumentMutationGuard {
1602
+ private running;
1603
+ private closed;
1604
+ run<T>(mutation: () => T): T;
1605
+ close(): void;
1606
+ }
1607
+ //#endregion
1495
1608
  //#region src/document/mirror-adapter.d.ts
1496
1609
  interface MirrorVideoDocumentOptions {
1497
1610
  peerId?: PeerID;
@@ -1507,22 +1620,31 @@ interface MirrorVideoDocumentOptions {
1507
1620
  * - `transact(edit, audit)` runs the whole op in one `mirror.setState` callback:
1508
1621
  * one diff, one `doc.commit` carrying the audit message. The callback edits an
1509
1622
  * immer draft, so a throw inside it discards the draft and never touches Loro
1510
- * (natural rollback) — no `guard` / `rollback` / `openTransaction` machinery.
1623
+ * (natural rollback) without a document checkout or compensating commit.
1511
1624
  * - mirror's `idSelector` (track items keyed by `part_id`) diffs reorders to
1512
1625
  * real Loro `move` ops on every lane, so per-item CRDT identity survives on
1513
1626
  * main and secondary tracks alike.
1514
1627
  */
1515
1628
  declare class MirrorVideoDocumentAdapter implements SemanticDocumentAdapter {
1516
1629
  readonly doc: LoroDoc;
1630
+ private readonly mutationGuard;
1517
1631
  private readonly mirror;
1518
- constructor(doc: LoroDoc);
1632
+ private disposed;
1633
+ constructor(doc: LoroDoc, mutationGuard?: DocumentMutationGuard);
1519
1634
  snapshot(): VideoDocument;
1520
1635
  /**
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).
1636
+ * Native Entity authority: placement is already solved by the Entity graph.
1637
+ *
1638
+ * The root check goes through `getShallowValue` first because `getMap` creates
1639
+ * the container on access — probing a legacy document for `medeo` would
1640
+ * otherwise mutate it, which a read must never do.
1524
1641
  */
1525
- hasContent(): boolean;
1642
+ isEntityDocument(): boolean;
1643
+ /**
1644
+ * Release mirror subscriptions; do not reuse this adapter afterwards.
1645
+ * The caller still owns the borrowed LoroDoc.
1646
+ */
1647
+ dispose(): void;
1526
1648
  /**
1527
1649
  * Apply one op as a single transaction. `edit` mutates the immer draft; mirror
1528
1650
  * diffs the result and commits once with the audit `message`. A throw in `edit`
@@ -1530,15 +1652,12 @@ declare class MirrorVideoDocumentAdapter implements SemanticDocumentAdapter {
1530
1652
  * skips the commit — matching the prior "empty op leaves no audit" behavior.
1531
1653
  */
1532
1654
  transact(edit: (draft: VideoDocumentDraft) => void, audit: TransactAudit): void;
1655
+ private assertActive;
1533
1656
  }
1534
1657
  /** Build a fresh Loro doc seeded with `document` through the mirror. */
1535
1658
  declare function createMirrorVideoDocument(document: VideoDocument, options?: MirrorVideoDocumentOptions): LoroDoc;
1536
1659
  /** Build a `MirrorVideoDocumentAdapter` over a fresh doc seeded with `document`. */
1537
1660
  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
1661
  //#endregion
1543
1662
  //#region src/document/plain-memory-adapter.d.ts
1544
1663
  /**
@@ -1552,6 +1671,12 @@ interface JournalEntry extends TransactAudit {
1552
1671
  interface PlainMemoryAdapterOptions {
1553
1672
  /** Underlying id mint; wrapped so each call inside a transact is journaled. */
1554
1673
  idFactory?: PartIdFactory;
1674
+ /**
1675
+ * Refuse every `transact`. Set when the seed document is an Entity projection:
1676
+ * its timeline is owned by the Entity graph, and the document itself no longer
1677
+ * states its provenance (business metadata left the CRDT), so the caller does.
1678
+ */
1679
+ readOnly?: boolean;
1555
1680
  }
1556
1681
  /**
1557
1682
  * Pure in-memory `SemanticDocumentAdapter` — no Loro/WASM. Holds a
@@ -1575,6 +1700,7 @@ declare class PlainMemoryAdapter implements SemanticDocumentAdapter {
1575
1700
  * use this so every minted id is appended to the current transact's list.
1576
1701
  */
1577
1702
  readonly idFactory: PartIdFactory;
1703
+ private readonly readOnly;
1578
1704
  constructor(document: VideoDocument, options?: PlainMemoryAdapterOptions);
1579
1705
  get journal(): readonly JournalEntry[];
1580
1706
  hasContent(): boolean;
@@ -1593,9 +1719,9 @@ declare function createPlainMemoryAdapter(document: VideoDocument, options?: Pla
1593
1719
  /**
1594
1720
  * Project the mirror state (`VideoDocumentDraft`) into the authoritative
1595
1721
  * `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
1722
+ * §4, reference/17 §4: timeline + a single `tracks` list + part_library), so this
1597
1723
  * is a near-identity — it reads `time_position` / `fallback_abs_ms` JSON blobs
1598
- * back into structured values and trims empty strings, nothing more.
1724
+ * back into structured values and selects content fields. Legacy meta is ignored.
1599
1725
  *
1600
1726
  * It maps only authoritative facts (RFC 02 §6): `part_id` + `time_position`. The
1601
1727
  * projection-derived `VideoDraft` read-view (absolute time, `part_aggregations`,
@@ -1671,19 +1797,6 @@ declare const partUnionSchema: z.ZodUnion<readonly [z.ZodObject<{
1671
1797
  }, z.core.$loose>;
1672
1798
  }, z.core.$loose>]>;
1673
1799
  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
1800
  timeline: z.ZodOptional<z.ZodObject<{
1688
1801
  unit_time_ms: z.ZodOptional<z.ZodNumber>;
1689
1802
  }, z.core.$loose>>;
@@ -1775,4 +1888,4 @@ declare const videoDocumentSchema: z.ZodObject<{
1775
1888
  }, z.core.$loose>]>>>;
1776
1889
  }, z.core.$loose>;
1777
1890
  //#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 };
1891
+ export { DerivedItemPosition as $, assertValidVideoDocument as A, VideoDocument as At, EntityRelationRows as B, CaptionStyle as Bt, isImplementedSemanticOpKind as C, SpeechOriginAssetSystem as Ct, PartIdFactory as D, TrackItem as Dt, ValidationError as E, Track as Et, ResolvedEntityTrack as F, VideoDraftPartUnion as Ft, ScriptTextSegment as G, TrackItem$1 as Gt, RelationRow as H, SpeedShift as Ht, resolveEntityTimelineLayout as I, effectiveVideoClipDurationMs as It, VoiceDescriptor as J, SequenceDuration as K, EntityTimelineProjectionDocument as L, speedOf as Lt, EntityTimelineTrackRole as M, VideoDocumentValidationIssueCode as Mt, ResolvedEntityClipPlacement as N, VideoDraft as Nt, generatePartId as O, TrackItemTimePosition as Ot, ResolvedEntityTimelineLayout as P, VideoDraftContent as Pt, buildInitialVideoDocument as Q, projectEntityTimeline as R, Attachment as Rt, SemanticOpKind as S, PartUnion as St, SnapshotReadable as T, Timeline as Tt, CaptionSegmentSelection as U, Timeline$1 as Ut, EntityRow as V, PartAggregation as Vt, CaptionStyleFields as W, Track$1 as Wt, JsonValue as X, JsonObject as Y, EntityId as Z, SemanticOpName as _, BgmPart as _t, PlainMemoryAdapter as a, LANE_KINDS_IN_STACK_ORDER as at, ImplementedSemanticOpKind as b, DEFAULT_UNIT_TIME_MS as bt, MirrorVideoDocumentAdapter as c, ensureLaneTrack as ct, createMirrorVideoDocumentAdapter as d, solveVideoDocument as dt, SpeechHostMap as et, CommitOptions as f, TrackDraft as ft, SemanticOpInput as g, videoDocumentMirrorSchema as gt, SemanticEditor as h, VideoDocumentMirrorSchema as ht, JournalEntry as i, toVideoDocument as it, validateVideoDocument as j, VideoDocumentValidationIssue as jt, VideoDocumentValidationError as k, VideoClipPart as kt, MirrorVideoDocumentOptions as l, findLaneTrack as lt, SemanticDocumentAdapter as m, VideoDocumentDraft as mt, videoDocumentSchema as n, derivePositionFromAbs as nt, PlainMemoryAdapterOptions as o, LaneKind as ot, OpActor as p, TrackItemDraft as pt, SequenceRange as q, readVideoDocumentFromDraft as r, fromVideoDocument as rt, createPlainMemoryAdapter as s, SolvedVideoDocument as st, partUnionSchema as t, buildSpeechHostMap as tt, createMirrorVideoDocument as u, laneTrackId as ut, TransactAudit as v, CaptionDisplayCue as vt, SchemaValidator as w, SpeechPart as wt, PlannedSemanticOpKind as x, PartKind as xt, IMPLEMENTED_SEMANTIC_OP_KINDS as y, CaptionPart as yt, EntityTimelineProjectionError as z, CaptionPart$1 as zt };