@mengine/medeo-client 1.2.1-alpha.4 → 1.2.1-alpha.6

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.
@@ -111,7 +111,7 @@ const speechPart = schema.LoroMap({
111
111
  volume: schema.Number(),
112
112
  audio_storage_key: schema.String(),
113
113
  origin_speech_id: schema.String(),
114
- voice: schema.String({ required: false }).transform(jsonTransform()),
114
+ voice: schema.String().transform(jsonTransform()),
115
115
  caption_ids: schema.String().transform(jsonTransform())
116
116
  }, { required: false });
117
117
  const captionStyle = schema.LoroMap({
@@ -322,71 +322,6 @@ function syncAggregatedClipsTimePosition(doc) {
322
322
  }
323
323
  }
324
324
  /**
325
- * Resolve authoritative `time_position` edges without inventing parents from
326
- * geometric overlap. Roots stay absolute/sequential; every anchored descendant
327
- * follows its declared parent, regardless of whether that parent is video, BGM,
328
- * or speech.
329
- */
330
- function resolveAnchoredClipsTimePosition(doc) {
331
- const items = [
332
- ...doc.main_track,
333
- ...doc.bgm_track,
334
- ...doc.speech_track,
335
- ...doc.caption_track
336
- ];
337
- const byPart = indexByPart(items);
338
- const resolved = /* @__PURE__ */ new Set();
339
- const visiting = /* @__PURE__ */ new Set();
340
- const resolve = (item) => {
341
- if (resolved.has(item.part_id)) return item.abs_time_position;
342
- if (visiting.has(item.part_id)) throw new Error(`anchored position cycle at ${item.part_id}`);
343
- visiting.add(item.part_id);
344
- const position = item.time_position;
345
- if (position.mode === "absolute") item.abs_time_position = Math.round(position.offsetMs);
346
- else if (position.mode === "anchored") {
347
- const parent = byPart.get(position.anchorPartId);
348
- if (parent != null) item.abs_time_position = resolve(parent) + Math.round(position.offsetMs);
349
- }
350
- visiting.delete(item.part_id);
351
- resolved.add(item.part_id);
352
- return item.abs_time_position;
353
- };
354
- for (const item of items) resolve(item);
355
- }
356
- /** Preserve the historical orphan fallback without re-parenting valid roots. */
357
- function recoverOrphanedSpeechAnchorsByTime(doc) {
358
- const placedPartIds = new Set([
359
- ...doc.main_track,
360
- ...doc.bgm_track,
361
- ...doc.speech_track,
362
- ...doc.caption_track
363
- ].map((item) => item.part_id));
364
- const ranges = doc.main_track.map((item) => ({
365
- part_id: item.part_id,
366
- start: item.abs_time_position,
367
- end: item.abs_time_position + partDurationMs(doc, item.part_id)
368
- }));
369
- if (ranges.length === 0) return;
370
- for (const speech of doc.speech_track) {
371
- const position = speech.time_position;
372
- if (position.mode !== "anchored" || placedPartIds.has(position.anchorPartId)) continue;
373
- const range = ranges.find((candidate) => candidate.start <= speech.abs_time_position && speech.abs_time_position < candidate.end) ?? (speech.abs_time_position < ranges[0].start ? ranges[0] : ranges[ranges.length - 1]);
374
- const relative = Math.max(0, Math.round(speech.abs_time_position - range.start));
375
- let aggregation = doc.aggregations.find((candidate) => candidate.body_part_id === range.part_id);
376
- if (aggregation == null) {
377
- aggregation = {
378
- body_part_id: range.part_id,
379
- attachments: []
380
- };
381
- doc.aggregations.push(aggregation);
382
- }
383
- aggregation.attachments.push({
384
- part_id: speech.part_id,
385
- relative_time_position: relative
386
- });
387
- }
388
- }
389
- /**
390
325
  * Reassign each speech to the video clip whose time range contains its start,
391
326
  * rebuilding `aggregations`. A speech before the first clip or after the last
392
327
  * falls back to the first / last clip respectively (FE: see §4 note — FE falls
@@ -589,14 +524,14 @@ function hostVideoOf(doc, speechPartId) {
589
524
  //#endregion
590
525
  //#region src/timeline-core/entrypoints.ts
591
526
  /**
592
- * The full solve pipeline: arrange → resolve declared parent edges →
593
- * resolve-overlap → fill-gaps → recalc. The single cascade the read-side projection runs; ops
527
+ * The full solve pipeline: arrange → sync → reassign → resolve-overlap →
528
+ * fill-gaps → recalc. The single cascade the read-side projection runs; ops
594
529
  * never call it (they write only facts — RFC 02 §7/§10).
595
530
  */
596
531
  function cascadeAfterVideoClipChanges(doc, makeEmptyPart) {
597
532
  arrangeMainTrackSeamlessly(doc);
598
- resolveAnchoredClipsTimePosition(doc);
599
- recoverOrphanedSpeechAnchorsByTime(doc);
533
+ syncAggregatedClipsTimePosition(doc);
534
+ reassignSpeechesToVideoClipsByTime(doc);
600
535
  resolveAllSpeechOverlaps(doc);
601
536
  fillMainTrackTimeGaps(doc, makeEmptyPart);
602
537
  recalculateTimelineDuration(doc);
@@ -670,7 +605,7 @@ function videoDocumentToTimelineDoc(document) {
670
605
  caption_track: captionItems,
671
606
  bgm_track: bgmItems,
672
607
  part_library: partLibrary,
673
- aggregations: seedAggregations([...mainItems, ...bgmItems], speechItems),
608
+ aggregations: seedAggregations(mainItems, speechItems),
674
609
  timeline: {
675
610
  duration_ms: 0,
676
611
  unit_time_ms: document.timeline?.unit_time_ms ?? 0
@@ -694,18 +629,19 @@ function seedAbs(position, fallbackAbsMs) {
694
629
  }
695
630
  }
696
631
  /**
697
- * Build the read-view `aggregations` parent-map from anchored speech items.
698
- * Video and BGM roots are both valid hosts; absolute speech roots have no entry.
699
- * Caption→speech ownership remains in `speech_part_id` / `caption_ids`.
632
+ * Build the cascade `aggregations` parent-map from anchored items: an anchored
633
+ * item's `anchorPartId` is the host's `part_id` (= `body_part_id`), `offsetMs`
634
+ * is `relative_time_position`. Only main-track (video) hosts form aggregations;
635
+ * caption→speech relations are recomputed by the cascade from `caption.start_ms`.
700
636
  */
701
- function seedAggregations(hostItems, speechItems) {
702
- const hostPartIds = new Set(hostItems.map((item) => item.part_id));
637
+ function seedAggregations(mainItems, speechItems) {
638
+ const mainPartIds = new Set(mainItems.map((item) => item.part_id));
703
639
  const byHost = /* @__PURE__ */ new Map();
704
640
  const order = [];
705
641
  for (const speech of speechItems) {
706
642
  if (speech.time_position.mode !== "anchored") continue;
707
643
  const host = speech.time_position.anchorPartId;
708
- if (!hostPartIds.has(host)) continue;
644
+ if (!mainPartIds.has(host)) continue;
709
645
  let aggregation = byHost.get(host);
710
646
  if (aggregation == null) {
711
647
  aggregation = {
@@ -870,7 +806,7 @@ const speechPartSchema = z.object({
870
806
  volume: finiteNumber,
871
807
  audio_storage_key: z.string(),
872
808
  origin_speech_id: z.string(),
873
- voice: z.unknown().optional(),
809
+ voice: z.unknown(),
874
810
  caption_ids: z.array(z.string())
875
811
  }).passthrough();
876
812
  const captionPartSchema = z.object({
@@ -1831,4 +1767,4 @@ function createPlainMemoryAdapter(document, options) {
1831
1767
  return new PlainMemoryAdapter(document, options);
1832
1768
  }
1833
1769
  //#endregion
1834
- export { resolveAllSpeechOverlaps as A, effectiveVideoClipDurationMs as B, solveVideoDocument as C, reassignSpeechesToVideoClipsByTime as D, fillMainTrackTimeGaps as E, isEmptyVideoClip as F, base64ToBytes as G, partUnionToDraft as H, partDurationMs as I, bytesToBase64 as K, safeDurationMs as L, resolveSpeechOverlapByShiftingVideos as M, syncAggregatedClipsTimePosition as N, recalculateTimelineDuration as O, TIMELINE_SKELETON_DURATION_MS as P, DEFAULT_UNIT_TIME_MS as R, laneTrackId as S, arrangeMainTrackSeamlessly as T, recordEntries as U, speedOf as V, videoDocumentMirrorSchema as W, partUnionSchema as _, createMirrorVideoDocument as a, ensureLaneTrack as b, readVideoDocumentFromDraft as c, derivePositionFromAbs as d, fromVideoDocument as f, validateVideoDocument as g, assertValidVideoDocument as h, MirrorVideoDocumentAdapter as i, resolveAnchoredClipsTimePosition as j, recoverOrphanedSpeechAnchorsByTime as k, buildInitialVideoDocument as l, VideoDocumentValidationError as m, createPlainMemoryAdapter as n, createMirrorVideoDocumentAdapter as o, toVideoDocument as p, generatePartId as r, writeVideoDocumentToDraft as s, PlainMemoryAdapter as t, buildSpeechHostMap as u, videoDocumentSchema as v, cascadeAfterVideoClipChanges as w, findLaneTrack as x, LANE_KINDS_IN_STACK_ORDER as y, VIDEO_DOCUMENT_SCHEMA_VERSION as z };
1770
+ export { resolveSpeechOverlapByShiftingVideos as A, partUnionToDraft as B, solveVideoDocument as C, reassignSpeechesToVideoClipsByTime as D, fillMainTrackTimeGaps as E, safeDurationMs as F, videoDocumentMirrorSchema as H, DEFAULT_UNIT_TIME_MS as I, VIDEO_DOCUMENT_SCHEMA_VERSION as L, TIMELINE_SKELETON_DURATION_MS as M, isEmptyVideoClip as N, recalculateTimelineDuration as O, partDurationMs as P, effectiveVideoClipDurationMs as R, laneTrackId as S, arrangeMainTrackSeamlessly as T, base64ToBytes as U, recordEntries as V, bytesToBase64 as W, partUnionSchema as _, createMirrorVideoDocument as a, ensureLaneTrack as b, readVideoDocumentFromDraft as c, derivePositionFromAbs as d, fromVideoDocument as f, validateVideoDocument as g, assertValidVideoDocument as h, MirrorVideoDocumentAdapter as i, syncAggregatedClipsTimePosition as j, resolveAllSpeechOverlaps as k, buildInitialVideoDocument as l, VideoDocumentValidationError as m, createPlainMemoryAdapter as n, createMirrorVideoDocumentAdapter as o, toVideoDocument as p, generatePartId as r, writeVideoDocumentToDraft as s, PlainMemoryAdapter as t, buildSpeechHostMap as u, videoDocumentSchema as v, cascadeAfterVideoClipChanges as w, findLaneTrack as x, LANE_KINDS_IN_STACK_ORDER as y, speedOf as z };
@@ -1,4 +1,4 @@
1
- import { A as MoveVideoClipsInput, B as MoveSpeechesInput, J as DeleteBgmInput, K as DeleteSpeechesInput, N as MoveVideoClipsByAnchorInput, O as ReplaceVideoClipContentInput, R as MoveBgmInput, S as SetBgmInput, T as ReplaceVideoClipSequenceInput, U as DeleteVideoClipsInput, X as ChangeSpeechScriptInput, Z as ChangeSpeechVoiceInput, b as SetCaptionStyleInput, ct as AddVideoClipsInput, et as AdjustVideoClipVolumeInput, g as SetVideoClipSpeedShiftInput, it as AdjustSpeechVolumeInput, nt as AdjustVideoClipDurationInput, ot as AdjustBgmVolumeInput, ut as AddSpeechesInput, v as SetCaptionVisibilityInput } from "./index-CiDSfSMi.js";
1
+ import { A as MoveVideoClipsInput, J as ChangeSpeechScriptInput, K as DeleteBgmInput, N as MoveVideoClipsByAnchorInput, O as ReplaceVideoClipContentInput, Q as AdjustVideoClipVolumeInput, R as MoveSpeechesInput, S as SetBgmInput, T as ReplaceVideoClipSequenceInput, V as DeleteVideoClipsInput, W as DeleteSpeechesInput, Y as ChangeSpeechVoiceInput, b as SetCaptionStyleInput, ct as AddSpeechesInput, et as AdjustVideoClipDurationInput, g as SetVideoClipSpeedShiftInput, it as AdjustBgmVolumeInput, nt as AdjustSpeechVolumeInput, ot as AddVideoClipsInput, v as SetCaptionVisibilityInput } from "./index-InEWX9rk.js";
2
2
  import { InferInputType } from "loro-mirror";
3
3
  import { z } from "zod";
4
4
  import { LoroDoc, PeerID } from "loro-crdt";
@@ -1025,7 +1025,6 @@ declare class SchemaValidator {
1025
1025
  validateChangeSpeechVoice(input: ChangeSpeechVoiceInput, doc: SnapshotReadable): void;
1026
1026
  validateDeleteSpeeches(input: DeleteSpeechesInput, doc: SnapshotReadable): void;
1027
1027
  validateMoveSpeeches(input: MoveSpeechesInput, doc: SnapshotReadable): void;
1028
- validateMoveBgm(input: MoveBgmInput, doc: SnapshotReadable): void;
1029
1028
  validateSetBgm(input: SetBgmInput, _doc: SnapshotReadable): void;
1030
1029
  validateDeleteBgm(input: DeleteBgmInput, _doc: SnapshotReadable): void;
1031
1030
  validateSetCaptionVisibility(input: SetCaptionVisibilityInput, _doc: SnapshotReadable): void;
@@ -1037,8 +1036,12 @@ declare class SchemaValidator {
1037
1036
  /** Each regenerated speech (re-TTS) must already exist in the document. */
1038
1037
  private assertSpeechesExist;
1039
1038
  /**
1040
- * Anchored speeches may follow a video or BGM root. A null anchor is an
1041
- * explicit absolute speech root. Missing and wrong-kind parents are rejected.
1039
+ * Each speech's `anchor_part_id` must point at a video clip that already
1040
+ * exists. A relative speech anchored to a missing clip cannot be positioned
1041
+ * by the projection and has no host to recover to (RFC 02 §4/§11.1), so the
1042
+ * write must be rejected rather than landing a dangling reference. (Restores
1043
+ * the dangling-reference guard the old `validateMaterializedPatch` carried;
1044
+ * ADR 0009.)
1042
1045
  */
1043
1046
  private assertAnchorsExist;
1044
1047
  private assertPartKind;
@@ -1073,7 +1076,7 @@ declare class SchemaValidator {
1073
1076
  * side-effect payload contract in
1074
1077
  * `docs/projects/medeo-integration/results/phase-4-side-effect-payload-contract.md`.
1075
1078
  */
1076
- type ImplementedSemanticOpKind = 'MoveVideoClips' | 'MoveVideoClipsByAnchor' | 'DeleteVideoClips' | 'AddVideoClips' | 'AdjustVideoClipVolume' | 'SetVideoClipSpeedShift' | 'ReplaceVideoClipContent' | 'ReplaceVideoClipSequence' | 'AdjustVideoClipDuration' | 'AddSpeeches' | 'DeleteSpeeches' | 'MoveSpeeches' | 'MoveBgm' | 'ChangeSpeechScript' | 'ChangeSpeechVoice' | 'AdjustSpeechVolume' | 'SetCaptionVisibility' | 'SetCaptionStyle' | 'SetBgm' | 'DeleteBgm' | 'AdjustBgmVolume';
1079
+ type ImplementedSemanticOpKind = 'MoveVideoClips' | 'MoveVideoClipsByAnchor' | 'DeleteVideoClips' | 'AddVideoClips' | 'AdjustVideoClipVolume' | 'SetVideoClipSpeedShift' | 'ReplaceVideoClipContent' | 'ReplaceVideoClipSequence' | 'AdjustVideoClipDuration' | 'AddSpeeches' | 'DeleteSpeeches' | 'MoveSpeeches' | 'ChangeSpeechScript' | 'ChangeSpeechVoice' | 'AdjustSpeechVolume' | 'SetCaptionVisibility' | 'SetCaptionStyle' | 'SetBgm' | 'DeleteBgm' | 'AdjustBgmVolume';
1077
1080
  /**
1078
1081
  * Operations on the roadmap but NOT yet implemented by `SemanticEditor`. Empty:
1079
1082
  * Phase 4 covers every op with a real entry point. Kept as a named type so the
@@ -1140,7 +1143,7 @@ interface CommitOptions {
1140
1143
  /** Author of this op; omitted for writes with no acting user (bootstrap, repair). */
1141
1144
  actor?: OpActor;
1142
1145
  }
1143
- type SemanticOpInput = MoveVideoClipsInput | MoveVideoClipsByAnchorInput | DeleteVideoClipsInput | AddVideoClipsInput | AdjustVideoClipVolumeInput | AdjustSpeechVolumeInput | AdjustBgmVolumeInput | SetVideoClipSpeedShiftInput | ReplaceVideoClipContentInput | ReplaceVideoClipSequenceInput | AdjustVideoClipDurationInput | AddSpeechesInput | DeleteSpeechesInput | MoveSpeechesInput | MoveBgmInput | SetCaptionVisibilityInput | SetCaptionStyleInput | SetBgmInput | DeleteBgmInput;
1146
+ type SemanticOpInput = MoveVideoClipsInput | MoveVideoClipsByAnchorInput | DeleteVideoClipsInput | AddVideoClipsInput | AdjustVideoClipVolumeInput | AdjustSpeechVolumeInput | AdjustBgmVolumeInput | SetVideoClipSpeedShiftInput | ReplaceVideoClipContentInput | ReplaceVideoClipSequenceInput | AdjustVideoClipDurationInput | AddSpeechesInput | DeleteSpeechesInput | MoveSpeechesInput | SetCaptionVisibilityInput | SetCaptionStyleInput | SetBgmInput | DeleteBgmInput;
1144
1147
  type SemanticOpName = ImplementedSemanticOpKind;
1145
1148
  /** Audit metadata committed alongside an op's writes. */
1146
1149
  interface TransactAudit {
@@ -1257,8 +1260,6 @@ declare class SemanticEditor {
1257
1260
  * derives absolute positions on read.
1258
1261
  */
1259
1262
  moveSpeeches(input: MoveSpeechesInput, options?: CommitOptions): Promise<void>;
1260
- /** Move the BGM root; any speech/caption descendants follow through their anchors. */
1261
- moveBgm(input: MoveBgmInput, options?: CommitOptions): Promise<void>;
1262
1263
  /** Change a speech's script. Re-TTS runs upstream; the regenerated parts arrive materialized (no cascade). */
1263
1264
  changeSpeechScript(input: ChangeSpeechScriptInput, options?: CommitOptions): Promise<void>;
1264
1265
  /** Change a speech's voice. Re-TTS runs upstream; the regenerated parts arrive materialized (no cascade). */
@@ -1455,7 +1456,7 @@ declare const partUnionSchema: z.ZodUnion<readonly [z.ZodObject<{
1455
1456
  volume: z.ZodNumber;
1456
1457
  audio_storage_key: z.ZodString;
1457
1458
  origin_speech_id: z.ZodString;
1458
- voice: z.ZodOptional<z.ZodUnknown>;
1459
+ voice: z.ZodUnknown;
1459
1460
  caption_ids: z.ZodArray<z.ZodString>;
1460
1461
  }, z.core.$loose>;
1461
1462
  }, z.core.$loose>, z.ZodObject<{
@@ -1555,7 +1556,7 @@ declare const videoDocumentSchema: z.ZodObject<{
1555
1556
  volume: z.ZodNumber;
1556
1557
  audio_storage_key: z.ZodString;
1557
1558
  origin_speech_id: z.ZodString;
1558
- voice: z.ZodOptional<z.ZodUnknown>;
1559
+ voice: z.ZodUnknown;
1559
1560
  caption_ids: z.ZodArray<z.ZodString>;
1560
1561
  }, z.core.$loose>;
1561
1562
  }, z.core.$loose>, z.ZodObject<{
@@ -11,16 +11,16 @@ import { z } from "zod";
11
11
  declare const addSpeechesInputSchema: z.ZodObject<{
12
12
  speeches: z.ZodArray<z.ZodObject<{
13
13
  speech_id: z.ZodString;
14
- anchor_part_id: z.ZodNullable<z.ZodString>;
14
+ anchor_part_id: z.ZodString;
15
15
  offset_ms: z.ZodNumber;
16
16
  audio_storage_key: z.ZodString;
17
17
  duration_ms: z.ZodNumber;
18
18
  audio_script: z.ZodString;
19
19
  volume: z.ZodNumber;
20
- voice: z.ZodOptional<z.ZodObject<{
20
+ voice: z.ZodObject<{
21
21
  id: z.ZodString;
22
22
  name: z.ZodString;
23
- }, z.core.$strip>>;
23
+ }, z.core.$strip>;
24
24
  origin_speech_id: z.ZodString;
25
25
  caption_ids: z.ZodArray<z.ZodString>;
26
26
  }, z.core.$strip>>;
@@ -116,16 +116,16 @@ type AdjustVideoClipVolumeInput = z.infer<typeof adjustVideoClipVolumeInputSchem
116
116
  declare const changeSpeechScriptInputSchema: z.ZodObject<{
117
117
  speeches: z.ZodArray<z.ZodObject<{
118
118
  speech_id: z.ZodString;
119
- anchor_part_id: z.ZodNullable<z.ZodString>;
119
+ anchor_part_id: z.ZodString;
120
120
  offset_ms: z.ZodNumber;
121
121
  audio_storage_key: z.ZodString;
122
122
  duration_ms: z.ZodNumber;
123
123
  audio_script: z.ZodString;
124
124
  volume: z.ZodNumber;
125
- voice: z.ZodOptional<z.ZodObject<{
125
+ voice: z.ZodObject<{
126
126
  id: z.ZodString;
127
127
  name: z.ZodString;
128
- }, z.core.$strip>>;
128
+ }, z.core.$strip>;
129
129
  origin_speech_id: z.ZodString;
130
130
  caption_ids: z.ZodArray<z.ZodString>;
131
131
  }, z.core.$strip>>;
@@ -140,16 +140,16 @@ declare const changeSpeechScriptInputSchema: z.ZodObject<{
140
140
  declare const changeSpeechVoiceInputSchema: z.ZodObject<{
141
141
  speeches: z.ZodArray<z.ZodObject<{
142
142
  speech_id: z.ZodString;
143
- anchor_part_id: z.ZodNullable<z.ZodString>;
143
+ anchor_part_id: z.ZodString;
144
144
  offset_ms: z.ZodNumber;
145
145
  audio_storage_key: z.ZodString;
146
146
  duration_ms: z.ZodNumber;
147
147
  audio_script: z.ZodString;
148
148
  volume: z.ZodNumber;
149
- voice: z.ZodOptional<z.ZodObject<{
149
+ voice: z.ZodObject<{
150
150
  id: z.ZodString;
151
151
  name: z.ZodString;
152
- }, z.core.$strip>>;
152
+ }, z.core.$strip>;
153
153
  origin_speech_id: z.ZodString;
154
154
  caption_ids: z.ZodArray<z.ZodString>;
155
155
  }, z.core.$strip>>;
@@ -219,12 +219,6 @@ declare const moveSpeechesInputSchema: z.ZodObject<{
219
219
  }, z.core.$strip>;
220
220
  type MoveSpeechesInput = z.infer<typeof moveSpeechesInputSchema>;
221
221
  //#endregion
222
- //#region src/editor/schemas/move-bgm.d.ts
223
- declare const moveBgmInputSchema: z.ZodObject<{
224
- new_start_ms: z.ZodNumber;
225
- }, z.core.$strip>;
226
- type MoveBgmInput = z.infer<typeof moveBgmInputSchema>;
227
- //#endregion
228
222
  //#region src/editor/schemas/move-video-clips-by-anchor.d.ts
229
223
  /**
230
224
  * Where the moved block lands on the main track.
@@ -551,23 +545,25 @@ declare const voiceSchema: z.ZodObject<{
551
545
  * stable speech + caption parts and writes them as authoritative facts. No
552
546
  * cascade runs on write — the projection derives absolute positions on read.
553
547
  *
554
- * `anchor_part_id` states the root relationship explicitly: a video/BGM id
555
- * creates an anchored speech; `null` creates an absolute audio root.
556
- * `offset_ms` is relative to the anchor or absolute for a root. Captions always
557
- * anchor to their speech via `start_ms`.
548
+ * Each speech carries the anchoring fact directly (RFC 02 §4): the host video
549
+ * clip `anchor_part_id` and the `offset_ms` within it. The upstream caller
550
+ * already knows which clip a speech attaches to, so the op writes
551
+ * `{ mode:'anchored', anchorPartId, offsetMs }` verbatim — no write-time
552
+ * host-picking. Captions anchor to their speech via the caption part's
553
+ * `start_ms` (offset within the speech).
558
554
  */
559
555
  declare const speechAssetSchema: z.ZodObject<{
560
556
  speech_id: z.ZodString;
561
- anchor_part_id: z.ZodNullable<z.ZodString>;
557
+ anchor_part_id: z.ZodString;
562
558
  offset_ms: z.ZodNumber;
563
559
  audio_storage_key: z.ZodString;
564
560
  duration_ms: z.ZodNumber;
565
561
  audio_script: z.ZodString;
566
562
  volume: z.ZodNumber;
567
- voice: z.ZodOptional<z.ZodObject<{
563
+ voice: z.ZodObject<{
568
564
  id: z.ZodString;
569
565
  name: z.ZodString;
570
- }, z.core.$strip>>;
566
+ }, z.core.$strip>;
571
567
  origin_speech_id: z.ZodString;
572
568
  caption_ids: z.ZodArray<z.ZodString>;
573
569
  }, z.core.$strip>;
@@ -582,16 +578,16 @@ declare const captionAssetSchema: z.ZodObject<{
582
578
  declare const speechAssetsSchema: z.ZodObject<{
583
579
  speeches: z.ZodArray<z.ZodObject<{
584
580
  speech_id: z.ZodString;
585
- anchor_part_id: z.ZodNullable<z.ZodString>;
581
+ anchor_part_id: z.ZodString;
586
582
  offset_ms: z.ZodNumber;
587
583
  audio_storage_key: z.ZodString;
588
584
  duration_ms: z.ZodNumber;
589
585
  audio_script: z.ZodString;
590
586
  volume: z.ZodNumber;
591
- voice: z.ZodOptional<z.ZodObject<{
587
+ voice: z.ZodObject<{
592
588
  id: z.ZodString;
593
589
  name: z.ZodString;
594
- }, z.core.$strip>>;
590
+ }, z.core.$strip>;
595
591
  origin_speech_id: z.ZodString;
596
592
  caption_ids: z.ZodArray<z.ZodString>;
597
593
  }, z.core.$strip>>;
@@ -607,7 +603,7 @@ type SpeechAsset = z.infer<typeof speechAssetSchema>;
607
603
  type CaptionAsset = z.infer<typeof captionAssetSchema>;
608
604
  type SpeechAssets = z.infer<typeof speechAssetsSchema>;
609
605
  declare namespace index_d_exports {
610
- export { AddSpeechesInput, AddVideoClipsInput, AdjustBgmVolumeInput, AdjustSpeechVolumeInput, AdjustVideoClipDurationInput, AdjustVideoClipVolumeInput, AnchoredDeletePolicy, AnchoredReplacePolicy, CaptionAsset, ChangeSpeechScriptInput, ChangeSpeechVoiceInput, DeleteBgmInput, DeleteSpeechesInput, DeleteVideoClipsInput, MoveAnchor, MoveBgmInput, MoveSpeechesInput, MoveVideoClipsByAnchorInput, MoveVideoClipsInput, MovedClipAnchoredPolicy, ReplaceVideoClipContentInput, ReplaceVideoClipSequenceInput, SetBgmInput, SetCaptionStyleInput, SetCaptionVisibilityInput, SetVideoClipSpeedShiftInput, SpeechAsset, SpeechAssets, addSpeechesInputSchema, addVideoClipsInputSchema, adjustBgmVolumeInputSchema, adjustSpeechVolumeInputSchema, adjustVideoClipDurationInputSchema, adjustVideoClipVolumeInputSchema, anchoredDeletePolicySchema, anchoredReplacePolicySchema, changeSpeechScriptInputSchema, changeSpeechVoiceInputSchema, clipIdSchema, clipIdsSchema, deleteBgmInputSchema, deleteSpeechesInputSchema, deleteVideoClipsInputSchema, mediaIdSchema, moveAnchorSchema, moveBgmInputSchema, moveSpeechesInputSchema, moveVideoClipsByAnchorInputSchema, moveVideoClipsInputSchema, movedClipAnchoredPolicySchema, positiveMsSchema, replaceVideoClipContentInputSchema, replaceVideoClipSequenceInputSchema, setBgmInputSchema, setCaptionStyleInputSchema, setCaptionVisibilityInputSchema, setVideoClipSpeedShiftInputSchema, speechAssetsSchema, speechIdSchema, speechIdsSchema, speedShiftSchema, timelineMsSchema, voiceSchema, volumeSchema };
606
+ export { AddSpeechesInput, AddVideoClipsInput, AdjustBgmVolumeInput, AdjustSpeechVolumeInput, AdjustVideoClipDurationInput, AdjustVideoClipVolumeInput, AnchoredDeletePolicy, AnchoredReplacePolicy, CaptionAsset, ChangeSpeechScriptInput, ChangeSpeechVoiceInput, DeleteBgmInput, DeleteSpeechesInput, DeleteVideoClipsInput, MoveAnchor, MoveSpeechesInput, MoveVideoClipsByAnchorInput, MoveVideoClipsInput, MovedClipAnchoredPolicy, ReplaceVideoClipContentInput, ReplaceVideoClipSequenceInput, SetBgmInput, SetCaptionStyleInput, SetCaptionVisibilityInput, SetVideoClipSpeedShiftInput, SpeechAsset, SpeechAssets, addSpeechesInputSchema, addVideoClipsInputSchema, adjustBgmVolumeInputSchema, adjustSpeechVolumeInputSchema, adjustVideoClipDurationInputSchema, adjustVideoClipVolumeInputSchema, anchoredDeletePolicySchema, anchoredReplacePolicySchema, changeSpeechScriptInputSchema, changeSpeechVoiceInputSchema, clipIdSchema, clipIdsSchema, deleteBgmInputSchema, deleteSpeechesInputSchema, deleteVideoClipsInputSchema, mediaIdSchema, moveAnchorSchema, moveSpeechesInputSchema, moveVideoClipsByAnchorInputSchema, moveVideoClipsInputSchema, movedClipAnchoredPolicySchema, positiveMsSchema, replaceVideoClipContentInputSchema, replaceVideoClipSequenceInputSchema, setBgmInputSchema, setCaptionStyleInputSchema, setCaptionVisibilityInputSchema, setVideoClipSpeedShiftInputSchema, speechAssetsSchema, speechIdSchema, speechIdsSchema, speedShiftSchema, timelineMsSchema, voiceSchema, volumeSchema };
611
607
  }
612
608
  //#endregion
613
- export { changeSpeechVoiceInputSchema as $, MoveVideoClipsInput as A, MoveSpeechesInput as B, setBgmInputSchema as C, replaceVideoClipSequenceInputSchema as D, anchoredReplacePolicySchema as E, moveAnchorSchema as F, deleteVideoClipsInputSchema as G, AnchoredDeletePolicy as H, moveVideoClipsByAnchorInputSchema as I, DeleteBgmInput as J, DeleteSpeechesInput as K, movedClipAnchoredPolicySchema as L, MoveAnchor as M, MoveVideoClipsByAnchorInput as N, ReplaceVideoClipContentInput as O, MovedClipAnchoredPolicy as P, changeSpeechScriptInputSchema as Q, MoveBgmInput as R, SetBgmInput as S, ReplaceVideoClipSequenceInput as T, DeleteVideoClipsInput as U, moveSpeechesInputSchema as V, anchoredDeletePolicySchema as W, ChangeSpeechScriptInput as X, deleteBgmInputSchema as Y, ChangeSpeechVoiceInput as Z, setVideoClipSpeedShiftInputSchema as _, speechAssetsSchema as a, adjustSpeechVolumeInputSchema as at, SetCaptionStyleInput as b, mediaIdSchema as c, AddVideoClipsInput as ct, speechIdsSchema as d, addSpeechesInputSchema as dt, AdjustVideoClipVolumeInput as et, speedShiftSchema as f, SetVideoClipSpeedShiftInput as g, volumeSchema as h, SpeechAssets as i, AdjustSpeechVolumeInput as it, moveVideoClipsInputSchema as j, replaceVideoClipContentInputSchema as k, positiveMsSchema as l, addVideoClipsInputSchema as lt, voiceSchema as m, CaptionAsset as n, AdjustVideoClipDurationInput as nt, clipIdSchema as o, AdjustBgmVolumeInput as ot, timelineMsSchema as p, deleteSpeechesInputSchema as q, SpeechAsset as r, adjustVideoClipDurationInputSchema as rt, clipIdsSchema as s, adjustBgmVolumeInputSchema as st, index_d_exports as t, adjustVideoClipVolumeInputSchema as tt, speechIdSchema as u, AddSpeechesInput as ut, SetCaptionVisibilityInput as v, AnchoredReplacePolicy as w, setCaptionStyleInputSchema as x, setCaptionVisibilityInputSchema as y, moveBgmInputSchema as z };
609
+ export { adjustVideoClipVolumeInputSchema as $, MoveVideoClipsInput as A, AnchoredDeletePolicy as B, setBgmInputSchema as C, replaceVideoClipSequenceInputSchema as D, anchoredReplacePolicySchema as E, moveAnchorSchema as F, deleteSpeechesInputSchema as G, anchoredDeletePolicySchema as H, moveVideoClipsByAnchorInputSchema as I, ChangeSpeechScriptInput as J, DeleteBgmInput as K, movedClipAnchoredPolicySchema as L, MoveAnchor as M, MoveVideoClipsByAnchorInput as N, ReplaceVideoClipContentInput as O, MovedClipAnchoredPolicy as P, AdjustVideoClipVolumeInput as Q, MoveSpeechesInput as R, SetBgmInput as S, ReplaceVideoClipSequenceInput as T, deleteVideoClipsInputSchema as U, DeleteVideoClipsInput as V, DeleteSpeechesInput as W, changeSpeechScriptInputSchema as X, ChangeSpeechVoiceInput as Y, changeSpeechVoiceInputSchema as Z, setVideoClipSpeedShiftInputSchema as _, speechAssetsSchema as a, adjustBgmVolumeInputSchema as at, SetCaptionStyleInput as b, mediaIdSchema as c, AddSpeechesInput as ct, speechIdsSchema as d, AdjustVideoClipDurationInput as et, speedShiftSchema as f, SetVideoClipSpeedShiftInput as g, volumeSchema as h, SpeechAssets as i, AdjustBgmVolumeInput as it, moveVideoClipsInputSchema as j, replaceVideoClipContentInputSchema as k, positiveMsSchema as l, addSpeechesInputSchema as lt, voiceSchema as m, CaptionAsset as n, AdjustSpeechVolumeInput as nt, clipIdSchema as o, AddVideoClipsInput as ot, timelineMsSchema as p, deleteBgmInputSchema as q, SpeechAsset as r, adjustSpeechVolumeInputSchema as rt, clipIdsSchema as s, addVideoClipsInputSchema as st, index_d_exports as t, adjustVideoClipDurationInputSchema as tt, speechIdSchema as u, SetCaptionVisibilityInput as v, AnchoredReplacePolicy as w, setCaptionStyleInputSchema as x, setCaptionVisibilityInputSchema as y, moveSpeechesInputSchema as z };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { t as index_d_exports } from "./index-CiDSfSMi.js";
2
- import { $ as Track, A as TrackDraft, B as DerivedItemPosition, C as SemanticOpKind, D as ValidationError, E as SnapshotReadable, F as VideoDocumentValidationError, G as toVideoDocument, H as buildSpeechHostMap, I as assertValidVideoDocument, J as DEFAULT_UNIT_TIME_MS, K as BgmPart, L as validateVideoDocument, M as VideoDocumentDraft, N as VideoDocumentMirrorSchema, O as PartIdFactory, P as videoDocumentMirrorSchema, Q as Timeline, R as InitialDocumentFacts, S as PlannedSemanticOpKind, T as SchemaValidator, U as derivePositionFromAbs, V as SpeechHostMap, W as fromVideoDocument, X as PartUnion, Y as PartKind, Z as SpeechPart, _ as SemanticOpInput, _t as Timeline$1, a as PlainMemoryAdapter, at as VideoDocumentSchemaVersion, b as IMPLEMENTED_SEMANTIC_OP_KINDS, c as MirrorVideoDocumentAdapter, ct as VideoDraft, d as createMirrorVideoDocumentAdapter, dt as speedOf, et as TrackItem, f as writeVideoDocumentToDraft, ft as Attachment, g as SemanticEditor, gt as SpeedShift, h as SemanticDocumentAdapter, ht as PartAggregation, i as JournalEntry, it as VideoDocument, j as TrackItemDraft, k as generatePartId, l as MirrorVideoDocumentOptions, lt as VideoDraftPartUnion, m as OpActor, mt as CaptionStyle, n as videoDocumentSchema, nt as VIDEO_DOCUMENT_SCHEMA_VERSION, o as PlainMemoryAdapterOptions, ot as VideoDocumentValidationIssue, p as CommitOptions, pt as CaptionPart$1, q as CaptionPart, r as readVideoDocumentFromDraft, rt as VideoClipPart, s as createPlainMemoryAdapter, st as VideoDocumentValidationIssueCode, t as partUnionSchema, tt as TrackItemTimePosition, u as createMirrorVideoDocument, ut as effectiveVideoClipDurationMs, v as SemanticOpName, vt as Track$1, w as isImplementedSemanticOpKind, x as ImplementedSemanticOpKind, y as TransactAudit, yt as TrackItem$1, z as buildInitialVideoDocument } from "./index-DkJ0JK2t.js";
1
+ import { t as index_d_exports } from "./index-InEWX9rk.js";
2
+ import { $ as Track, A as TrackDraft, B as DerivedItemPosition, C as SemanticOpKind, D as ValidationError, E as SnapshotReadable, F as VideoDocumentValidationError, G as toVideoDocument, H as buildSpeechHostMap, I as assertValidVideoDocument, J as DEFAULT_UNIT_TIME_MS, K as BgmPart, L as validateVideoDocument, M as VideoDocumentDraft, N as VideoDocumentMirrorSchema, O as PartIdFactory, P as videoDocumentMirrorSchema, Q as Timeline, R as InitialDocumentFacts, S as PlannedSemanticOpKind, T as SchemaValidator, U as derivePositionFromAbs, V as SpeechHostMap, W as fromVideoDocument, X as PartUnion, Y as PartKind, Z as SpeechPart, _ as SemanticOpInput, _t as Timeline$1, a as PlainMemoryAdapter, at as VideoDocumentSchemaVersion, b as IMPLEMENTED_SEMANTIC_OP_KINDS, c as MirrorVideoDocumentAdapter, ct as VideoDraft, d as createMirrorVideoDocumentAdapter, dt as speedOf, et as TrackItem, f as writeVideoDocumentToDraft, ft as Attachment, g as SemanticEditor, gt as SpeedShift, h as SemanticDocumentAdapter, ht as PartAggregation, i as JournalEntry, it as VideoDocument, j as TrackItemDraft, k as generatePartId, l as MirrorVideoDocumentOptions, lt as VideoDraftPartUnion, m as OpActor, mt as CaptionStyle, n as videoDocumentSchema, nt as VIDEO_DOCUMENT_SCHEMA_VERSION, o as PlainMemoryAdapterOptions, ot as VideoDocumentValidationIssue, p as CommitOptions, pt as CaptionPart$1, q as CaptionPart, r as readVideoDocumentFromDraft, rt as VideoClipPart, s as createPlainMemoryAdapter, st as VideoDocumentValidationIssueCode, t as partUnionSchema, tt as TrackItemTimePosition, u as createMirrorVideoDocument, ut as effectiveVideoClipDurationMs, v as SemanticOpName, vt as Track$1, w as isImplementedSemanticOpKind, x as ImplementedSemanticOpKind, y as TransactAudit, yt as TrackItem$1, z as buildInitialVideoDocument } from "./index-BO2fSUKi.js";
3
3
  import { PeerID } from "loro-crdt";
4
4
  import { DocState } from "@mengine/sync";
5
5
  import { BaseDocStorage, Connection, DocDiff, DocPushReceipt, DocSnapshotRecord, DocStorage, DocStorageOptions, DocUpdate, DocUpdateRecord } from "@mengine/storage";
@@ -866,15 +866,6 @@ declare function arrangeMainTrackSeamlessly(doc: TimelineDoc): void;
866
866
  * caption.abs = speech.abs + caption.start_ms
867
867
  */
868
868
  declare function syncAggregatedClipsTimePosition(doc: TimelineDoc): void;
869
- /**
870
- * Resolve authoritative `time_position` edges without inventing parents from
871
- * geometric overlap. Roots stay absolute/sequential; every anchored descendant
872
- * follows its declared parent, regardless of whether that parent is video, BGM,
873
- * or speech.
874
- */
875
- declare function resolveAnchoredClipsTimePosition(doc: TimelineDoc): void;
876
- /** Preserve the historical orphan fallback without re-parenting valid roots. */
877
- declare function recoverOrphanedSpeechAnchorsByTime(doc: TimelineDoc): void;
878
869
  /**
879
870
  * Reassign each speech to the video clip whose time range contains its start,
880
871
  * rebuilding `aggregations`. A speech before the first clip or after the last
@@ -940,8 +931,8 @@ type MakeEmptyPart = (durationMs: number) => {
940
931
  partId: string;
941
932
  };
942
933
  /**
943
- * The full solve pipeline: arrange → resolve declared parent edges →
944
- * resolve-overlap → fill-gaps → recalc. The single cascade the read-side projection runs; ops
934
+ * The full solve pipeline: arrange → sync → reassign → resolve-overlap →
935
+ * fill-gaps → recalc. The single cascade the read-side projection runs; ops
945
936
  * never call it (they write only facts — RFC 02 §7/§10).
946
937
  */
947
938
  declare function cascadeAfterVideoClipChanges(doc: TimelineDoc, makeEmptyPart: MakeEmptyPart): void;
@@ -1086,4 +1077,4 @@ declare function hostForAbsMs(ranges: MainClipRange[], absMs: number): MainClipR
1086
1077
  */
1087
1078
  declare function relativePositionForAbs(ranges: MainClipRange[], absMs: number): TrackItemTimePosition;
1088
1079
  //#endregion
1089
- export { type Aggregation, type Attachment, type BgmPart, type CaptionPart, type CaptionStyle, type CommitOptions, DEFAULT_UNIT_TIME_MS, type DerivedItemPosition, type DocStorageLike, type DocVersionMark, IMPLEMENTED_SEMANTIC_OP_KINDS, type ImplementedSemanticOpKind, type InitialDocumentFacts, type JournalEntry, LANE_KINDS_IN_STACK_ORDER, type LaneKind, type MainClipRange, type MakeEmptyPart, ManualSyncDoc, type ManualSyncDocOptions, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, MemoryDocStorage, MengineAckFailedError, type MengineAuditEntry, type MengineAuditResponse, MengineDocSession, type MengineDocSessionOptions, type MengineDocSessionUpdateEvent, type MengineDocumentVersion, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUpdateMeta, MirrorVideoDocumentAdapter, type MirrorVideoDocumentOptions, type OpActor, type PartAggregation, type PartIdFactory, type PartKind, type PartUnion, PlainMemoryAdapter, type PlainMemoryAdapterOptions, type PlannedSemanticOpKind, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, SchemaValidator, type SemanticDocumentAdapter, SemanticEditor, type SemanticOpInput, type SemanticOpKind, type SemanticOpName, type SnapshotReadable, type SolvedVideoDocument, type SpeechHostMap, type SpeechPart, type SpeedShift, TIMELINE_SKELETON_DURATION_MS, type Timeline, type TimelineDoc, type TimelineItem, type Track, type TrackDraft, type TrackItem, type TrackItemDraft, type TrackItemTimePosition, type TransactAudit, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, type VideoClipPart, type VideoDocument, type VideoDocumentDraft, type VideoDocumentMirrorSchema, type VideoDocumentSchemaVersion, VideoDocumentValidationError, type VideoDocumentValidationIssue, type VideoDocumentValidationIssueCode, type VideoDraft, type CaptionPart$1 as VideoDraftCaptionPart, type VideoDraftPartUnion, type Timeline$1 as VideoDraftTimeline, type Track$1 as VideoDraftTrack, type TrackItem$1 as VideoDraftTrackItem, type WaitForServerAckOptions, arrangeMainTrackSeamlessly, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureLaneTrack, fillMainTrackTimeGaps, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, partDurationMs, partUnionSchema, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, recoverOrphanedSpeechAnchorsByTime, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveAnchoredClipsTimePosition, resolveSpeechOverlapByShiftingVideos, safeDurationMs, index_d_exports as schemas, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
1080
+ export { type Aggregation, type Attachment, type BgmPart, type CaptionPart, type CaptionStyle, type CommitOptions, DEFAULT_UNIT_TIME_MS, type DerivedItemPosition, type DocStorageLike, type DocVersionMark, IMPLEMENTED_SEMANTIC_OP_KINDS, type ImplementedSemanticOpKind, type InitialDocumentFacts, type JournalEntry, LANE_KINDS_IN_STACK_ORDER, type LaneKind, type MainClipRange, type MakeEmptyPart, ManualSyncDoc, type ManualSyncDocOptions, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, MemoryDocStorage, MengineAckFailedError, type MengineAuditEntry, type MengineAuditResponse, MengineDocSession, type MengineDocSessionOptions, type MengineDocSessionUpdateEvent, type MengineDocumentVersion, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUpdateMeta, MirrorVideoDocumentAdapter, type MirrorVideoDocumentOptions, type OpActor, type PartAggregation, type PartIdFactory, type PartKind, type PartUnion, PlainMemoryAdapter, type PlainMemoryAdapterOptions, type PlannedSemanticOpKind, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, SchemaValidator, type SemanticDocumentAdapter, SemanticEditor, type SemanticOpInput, type SemanticOpKind, type SemanticOpName, type SnapshotReadable, type SolvedVideoDocument, type SpeechHostMap, type SpeechPart, type SpeedShift, TIMELINE_SKELETON_DURATION_MS, type Timeline, type TimelineDoc, type TimelineItem, type Track, type TrackDraft, type TrackItem, type TrackItemDraft, type TrackItemTimePosition, type TransactAudit, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, type VideoClipPart, type VideoDocument, type VideoDocumentDraft, type VideoDocumentMirrorSchema, type VideoDocumentSchemaVersion, VideoDocumentValidationError, type VideoDocumentValidationIssue, type VideoDocumentValidationIssueCode, type VideoDraft, type CaptionPart$1 as VideoDraftCaptionPart, type VideoDraftPartUnion, type Timeline$1 as VideoDraftTimeline, type Track$1 as VideoDraftTrack, type TrackItem$1 as VideoDraftTrackItem, type WaitForServerAckOptions, arrangeMainTrackSeamlessly, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureLaneTrack, fillMainTrackTimeGaps, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, partDurationMs, partUnionSchema, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveSpeechOverlapByShiftingVideos, safeDurationMs, index_d_exports as schemas, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { A as resolveAllSpeechOverlaps, B as effectiveVideoClipDurationMs, C as solveVideoDocument, D as reassignSpeechesToVideoClipsByTime, E as fillMainTrackTimeGaps, F as isEmptyVideoClip, G as base64ToBytes, H as partUnionToDraft, I as partDurationMs, K as bytesToBase64, L as safeDurationMs, M as resolveSpeechOverlapByShiftingVideos, N as syncAggregatedClipsTimePosition, O as recalculateTimelineDuration, P as TIMELINE_SKELETON_DURATION_MS, R as DEFAULT_UNIT_TIME_MS, S as laneTrackId, T as arrangeMainTrackSeamlessly, U as recordEntries, V as speedOf, W as videoDocumentMirrorSchema, _ as partUnionSchema, a as createMirrorVideoDocument, b as ensureLaneTrack, c as readVideoDocumentFromDraft, d as derivePositionFromAbs, f as fromVideoDocument, g as validateVideoDocument, h as assertValidVideoDocument, i as MirrorVideoDocumentAdapter, j as resolveAnchoredClipsTimePosition, k as recoverOrphanedSpeechAnchorsByTime, l as buildInitialVideoDocument, m as VideoDocumentValidationError, n as createPlainMemoryAdapter, o as createMirrorVideoDocumentAdapter, p as toVideoDocument, r as generatePartId, s as writeVideoDocumentToDraft, t as PlainMemoryAdapter, u as buildSpeechHostMap, v as videoDocumentSchema, w as cascadeAfterVideoClipChanges, x as findLaneTrack, y as LANE_KINDS_IN_STACK_ORDER, z as VIDEO_DOCUMENT_SCHEMA_VERSION } from "./document-C-h5-rCG.js";
2
- import { addSpeechesInputSchema, addVideoClipsInputSchema, adjustBgmVolumeInputSchema, adjustSpeechVolumeInputSchema, adjustVideoClipDurationInputSchema, adjustVideoClipVolumeInputSchema, changeSpeechScriptInputSchema, changeSpeechVoiceInputSchema, deleteBgmInputSchema, deleteSpeechesInputSchema, deleteVideoClipsInputSchema, moveBgmInputSchema, moveSpeechesInputSchema, moveVideoClipsByAnchorInputSchema, moveVideoClipsInputSchema, replaceVideoClipContentInputSchema, replaceVideoClipSequenceInputSchema, setBgmInputSchema, setCaptionStyleInputSchema, setCaptionVisibilityInputSchema, setVideoClipSpeedShiftInputSchema, t as schemas_exports } from "./schemas.js";
1
+ import { A as resolveSpeechOverlapByShiftingVideos, B as partUnionToDraft, C as solveVideoDocument, D as reassignSpeechesToVideoClipsByTime, E as fillMainTrackTimeGaps, F as safeDurationMs, H as videoDocumentMirrorSchema, I as DEFAULT_UNIT_TIME_MS, L as VIDEO_DOCUMENT_SCHEMA_VERSION, M as TIMELINE_SKELETON_DURATION_MS, N as isEmptyVideoClip, O as recalculateTimelineDuration, P as partDurationMs, R as effectiveVideoClipDurationMs, S as laneTrackId, T as arrangeMainTrackSeamlessly, U as base64ToBytes, V as recordEntries, W as bytesToBase64, _ as partUnionSchema, a as createMirrorVideoDocument, b as ensureLaneTrack, c as readVideoDocumentFromDraft, d as derivePositionFromAbs, f as fromVideoDocument, g as validateVideoDocument, h as assertValidVideoDocument, i as MirrorVideoDocumentAdapter, j as syncAggregatedClipsTimePosition, k as resolveAllSpeechOverlaps, l as buildInitialVideoDocument, m as VideoDocumentValidationError, n as createPlainMemoryAdapter, o as createMirrorVideoDocumentAdapter, p as toVideoDocument, r as generatePartId, s as writeVideoDocumentToDraft, t as PlainMemoryAdapter, u as buildSpeechHostMap, v as videoDocumentSchema, w as cascadeAfterVideoClipChanges, x as findLaneTrack, y as LANE_KINDS_IN_STACK_ORDER, z as speedOf } from "./document-49OdvviW.js";
2
+ import { addSpeechesInputSchema, addVideoClipsInputSchema, adjustBgmVolumeInputSchema, adjustSpeechVolumeInputSchema, adjustVideoClipDurationInputSchema, adjustVideoClipVolumeInputSchema, changeSpeechScriptInputSchema, changeSpeechVoiceInputSchema, deleteBgmInputSchema, deleteSpeechesInputSchema, deleteVideoClipsInputSchema, moveSpeechesInputSchema, moveVideoClipsByAnchorInputSchema, moveVideoClipsInputSchema, replaceVideoClipContentInputSchema, replaceVideoClipSequenceInputSchema, setBgmInputSchema, setCaptionStyleInputSchema, setCaptionVisibilityInputSchema, setVideoClipSpeedShiftInputSchema, t as schemas_exports } from "./schemas.js";
3
3
  import { LoroDoc, VersionVector } from "loro-crdt";
4
4
  import { ClientServerSynchronizer, DocManager } from "@mengine/sync";
5
5
  import { DisposableSet, EventBus, Task } from "@mengine/utils";
@@ -445,10 +445,6 @@ var SchemaValidator = class {
445
445
  const snapshot = doc.snapshot();
446
446
  for (const s of parsed.speeches) this.assertPartKind(snapshot, s.speech_id, "speech", "move_speeches");
447
447
  }
448
- validateMoveBgm(input, doc) {
449
- this.parse(moveBgmInputSchema, input, "move_bgm_invalid_input");
450
- if (doc.snapshot().tracks?.find((track) => track.parts_kind === "bgm")?.items?.[0] == null) throw new ValidationError("move_bgm_not_found", "document has no BGM item");
451
- }
452
448
  validateSetBgm(input, _doc) {
453
449
  this.parse(setBgmInputSchema, input, "set_bgm_invalid_input");
454
450
  }
@@ -484,20 +480,16 @@ var SchemaValidator = class {
484
480
  for (const speech of assets.speeches) this.assertPartKind(snapshot, speech.speech_id, "speech", opName);
485
481
  }
486
482
  /**
487
- * Anchored speeches may follow a video or BGM root. A null anchor is an
488
- * explicit absolute speech root. Missing and wrong-kind parents are rejected.
483
+ * Each speech's `anchor_part_id` must point at a video clip that already
484
+ * exists. A relative speech anchored to a missing clip cannot be positioned
485
+ * by the projection and has no host to recover to (RFC 02 §4/§11.1), so the
486
+ * write must be rejected rather than landing a dangling reference. (Restores
487
+ * the dangling-reference guard the old `validateMaterializedPatch` carried;
488
+ * ADR 0009.)
489
489
  */
490
490
  assertAnchorsExist(assets, doc, opName) {
491
491
  const snapshot = doc.snapshot();
492
- for (const speech of assets.speeches) {
493
- if (speech.anchor_part_id == null) continue;
494
- const part = readPart(snapshot, speech.anchor_part_id);
495
- if (part == null) throw new ValidationError(`${opName}_anchor_part_not_found`, `part_library has no parent`, { part_id: speech.anchor_part_id });
496
- if (part.part_kind !== "video_clip" && part.part_kind !== "bgm") throw new ValidationError(`${opName}_anchor_wrong_part_kind`, `speech parent must be video_clip or bgm`, {
497
- part_id: speech.anchor_part_id,
498
- part_kind: part.part_kind
499
- });
500
- }
492
+ for (const speech of assets.speeches) this.assertPartKind(snapshot, speech.anchor_part_id, "video_clip", `${opName}_anchor`);
501
493
  }
502
494
  assertPartKind(snapshot, partId, kind, opName) {
503
495
  const part = readPart(snapshot, partId);
@@ -846,9 +838,8 @@ var SemanticEditor = class {
846
838
  */
847
839
  async addSpeeches(input, options) {
848
840
  this.validator.validateAddSpeeches(input, this.doc);
849
- const absByPartId = solveVideoDocument(this.doc.snapshot()).absByPartId;
850
841
  this.doc.transact((draft) => {
851
- writeSpeechAssets(draft, input, absByPartId);
842
+ writeSpeechAssets(draft, input);
852
843
  }, audit("AddSpeeches", input, options));
853
844
  }
854
845
  /** Delete speeches with their captions; the subtree is removed (§9.2). Surviving lanes keep their facts. */
@@ -866,60 +857,29 @@ var SemanticEditor = class {
866
857
  */
867
858
  async moveSpeeches(input, options) {
868
859
  this.validator.validateMoveSpeeches(input, this.doc);
869
- const snapshot = this.doc.snapshot();
870
- const absByPartId = solveVideoDocument(snapshot).absByPartId;
871
860
  this.doc.transact((draft) => {
872
- const track = findLaneTrack(draft, "speech");
873
861
  const ranges = mainTrackRanges(draft);
862
+ const track = findLaneTrack(draft, "speech");
874
863
  for (const move of input.speeches) {
875
864
  const item = (track?.items ?? []).find((it) => it?.part_id === move.speech_id);
876
865
  if (item == null) continue;
877
- const current = item.time_position;
878
- if (current?.mode === "anchored") {
879
- const parentStartMs = absByPartId.get(current.anchorPartId);
880
- item.time_position = readPart(snapshot, current.anchorPartId)?.part_kind === "video_clip" ? relativePositionForAbs(ranges, move.new_start_ms) : parentStartMs == null ? {
881
- mode: "absolute",
882
- offsetMs: move.new_start_ms
883
- } : {
884
- mode: "anchored",
885
- anchorPartId: current.anchorPartId,
886
- offsetMs: Math.max(0, move.new_start_ms - parentStartMs)
887
- };
888
- } else item.time_position = {
889
- mode: "absolute",
890
- offsetMs: move.new_start_ms
891
- };
866
+ item.time_position = relativePositionForAbs(ranges, move.new_start_ms);
892
867
  item.fallback_abs_ms = move.new_start_ms;
893
868
  }
894
869
  }, audit("MoveSpeeches", input, options));
895
870
  }
896
- /** Move the BGM root; any speech/caption descendants follow through their anchors. */
897
- async moveBgm(input, options) {
898
- this.validator.validateMoveBgm(input, this.doc);
899
- this.doc.transact((draft) => {
900
- const item = findLaneTrack(draft, "bgm")?.items?.[0];
901
- if (item == null) return;
902
- item.time_position = {
903
- mode: "absolute",
904
- offsetMs: input.new_start_ms
905
- };
906
- item.fallback_abs_ms = void 0;
907
- }, audit("MoveBgm", input, options));
908
- }
909
871
  /** Change a speech's script. Re-TTS runs upstream; the regenerated parts arrive materialized (no cascade). */
910
872
  async changeSpeechScript(input, options) {
911
873
  this.validator.validateChangeSpeechScript(input, this.doc);
912
- const absByPartId = solveVideoDocument(this.doc.snapshot()).absByPartId;
913
874
  this.doc.transact((draft) => {
914
- writeSpeechAssets(draft, input, absByPartId);
875
+ writeSpeechAssets(draft, input);
915
876
  }, audit("ChangeSpeechScript", input, options));
916
877
  }
917
878
  /** Change a speech's voice. Re-TTS runs upstream; the regenerated parts arrive materialized (no cascade). */
918
879
  async changeSpeechVoice(input, options) {
919
880
  this.validator.validateChangeSpeechVoice(input, this.doc);
920
- const absByPartId = solveVideoDocument(this.doc.snapshot()).absByPartId;
921
881
  this.doc.transact((draft) => {
922
- writeSpeechAssets(draft, input, absByPartId);
882
+ writeSpeechAssets(draft, input);
923
883
  }, audit("ChangeSpeechVoice", input, options));
924
884
  }
925
885
  /**
@@ -1148,7 +1108,7 @@ function normalizeSpeedShift(input) {
1148
1108
  * projection derives it on read. On re-TTS the speech id is preserved, so an
1149
1109
  * existing item is re-positioned rather than duplicated.
1150
1110
  */
1151
- function writeSpeechAssets(draft, assets, absByPartId) {
1111
+ function writeSpeechAssets(draft, assets) {
1152
1112
  const captionById = new Map(assets.captions.map((c) => [c.caption_id, c]));
1153
1113
  const speechTrack = ensureLaneTrack(draft, "speech");
1154
1114
  speechTrack.items ??= [];
@@ -1161,6 +1121,8 @@ function writeSpeechAssets(draft, assets, absByPartId) {
1161
1121
  }
1162
1122
  return captionItems;
1163
1123
  };
1124
+ const ranges = mainTrackRanges(draft);
1125
+ const hostStartMs = (anchorPartId) => ranges.find((r) => r.partId === anchorPartId)?.startMs;
1164
1126
  for (const speech of assets.speeches) {
1165
1127
  const priorCaptionIds = draft.part_library?.[speech.speech_id]?.speech?.caption_ids ?? [];
1166
1128
  const nextCaptionIds = new Set(speech.caption_ids);
@@ -1184,10 +1146,9 @@ function writeSpeechAssets(draft, assets, absByPartId) {
1184
1146
  voice: speech.voice,
1185
1147
  caption_ids: speech.caption_ids
1186
1148
  } });
1187
- const hostStart = speech.anchor_part_id == null ? void 0 : absByPartId.get(speech.anchor_part_id);
1188
- const speechAbs = speech.anchor_part_id == null ? speech.offset_ms : hostStart == null ? void 0 : hostStart + speech.offset_ms;
1189
- if (speech.anchor_part_id == null) placeAbsolute(speechTrack.items, speech.speech_id, speech.offset_ms);
1190
- else placeRelative(speechTrack.items, speech.speech_id, speech.anchor_part_id, speech.offset_ms, speechAbs);
1149
+ const hostStart = hostStartMs(speech.anchor_part_id);
1150
+ const speechAbs = hostStart == null ? void 0 : hostStart + speech.offset_ms;
1151
+ placeRelative(speechTrack.items, speech.speech_id, speech.anchor_part_id, speech.offset_ms, speechAbs);
1191
1152
  for (const captionId of speech.caption_ids) {
1192
1153
  const caption = captionById.get(captionId);
1193
1154
  if (caption == null) continue;
@@ -1232,23 +1193,6 @@ function placeRelative(items, partId, anchorPartId, offsetMs, fallbackAbsMs) {
1232
1193
  fallback_abs_ms: fallbackAbsMs
1233
1194
  });
1234
1195
  }
1235
- function placeAbsolute(items, partId, startMs) {
1236
- const timePosition = {
1237
- mode: "absolute",
1238
- offsetMs: Math.max(0, Math.round(startMs))
1239
- };
1240
- const existing = items.find((item) => item?.part_id === partId);
1241
- if (existing != null) {
1242
- existing.time_position = timePosition;
1243
- existing.fallback_abs_ms = void 0;
1244
- return;
1245
- }
1246
- items.push({
1247
- part_id: partId,
1248
- time_position: timePosition,
1249
- fallback_abs_ms: void 0
1250
- });
1251
- }
1252
1196
  /**
1253
1197
  * After the main-track flow order changes (move / reorder), re-parent each
1254
1198
  * anchored speech to the clip its *preserved* absolute landing now falls in
@@ -1446,9 +1390,6 @@ async function dispatchEntry(editor, entry) {
1446
1390
  case "MoveSpeeches":
1447
1391
  await editor.moveSpeeches(payload, options);
1448
1392
  return;
1449
- case "MoveBgm":
1450
- await editor.moveBgm(payload, options);
1451
- return;
1452
1393
  case "ChangeSpeechScript":
1453
1394
  await editor.changeSpeechScript(payload, options);
1454
1395
  return;
@@ -1495,7 +1436,6 @@ const IMPLEMENTED_SEMANTIC_OP_KINDS = [
1495
1436
  "AddSpeeches",
1496
1437
  "DeleteSpeeches",
1497
1438
  "MoveSpeeches",
1498
- "MoveBgm",
1499
1439
  "ChangeSpeechScript",
1500
1440
  "ChangeSpeechVoice",
1501
1441
  "AdjustSpeechVolume",
@@ -2414,4 +2354,4 @@ function serverCovers(serverVV, target) {
2414
2354
  return covers(server, target);
2415
2355
  }
2416
2356
  //#endregion
2417
- export { DEFAULT_UNIT_TIME_MS, IMPLEMENTED_SEMANTIC_OP_KINDS, LANE_KINDS_IN_STACK_ORDER, ManualSyncDoc, MedeoHttpDocStorage, MemoryDocStorage, MengineAckFailedError, MengineDocSession, MengineHttpClient, MengineHttpRequestError, MenginePushRejectedError, MirrorVideoDocumentAdapter, PlainMemoryAdapter, SchemaValidator, SemanticEditor, TIMELINE_SKELETON_DURATION_MS, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, VideoDocumentValidationError, arrangeMainTrackSeamlessly, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureLaneTrack, fillMainTrackTimeGaps, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, partDurationMs, partUnionSchema, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, recoverOrphanedSpeechAnchorsByTime, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveAnchoredClipsTimePosition, resolveSpeechOverlapByShiftingVideos, safeDurationMs, schemas_exports as schemas, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
2357
+ export { DEFAULT_UNIT_TIME_MS, IMPLEMENTED_SEMANTIC_OP_KINDS, LANE_KINDS_IN_STACK_ORDER, ManualSyncDoc, MedeoHttpDocStorage, MemoryDocStorage, MengineAckFailedError, MengineDocSession, MengineHttpClient, MengineHttpRequestError, MenginePushRejectedError, MirrorVideoDocumentAdapter, PlainMemoryAdapter, SchemaValidator, SemanticEditor, TIMELINE_SKELETON_DURATION_MS, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, VideoDocumentValidationError, arrangeMainTrackSeamlessly, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureLaneTrack, fillMainTrackTimeGaps, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, partDurationMs, partUnionSchema, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveSpeechOverlapByShiftingVideos, safeDurationMs, schemas_exports as schemas, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
package/dist/schemas.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as changeSpeechVoiceInputSchema, A as MoveVideoClipsInput, B as MoveSpeechesInput, C as setBgmInputSchema, D as replaceVideoClipSequenceInputSchema, E as anchoredReplacePolicySchema, F as moveAnchorSchema, G as deleteVideoClipsInputSchema, H as AnchoredDeletePolicy, I as moveVideoClipsByAnchorInputSchema, J as DeleteBgmInput, K as DeleteSpeechesInput, L as movedClipAnchoredPolicySchema, M as MoveAnchor, N as MoveVideoClipsByAnchorInput, O as ReplaceVideoClipContentInput, P as MovedClipAnchoredPolicy, Q as changeSpeechScriptInputSchema, R as MoveBgmInput, S as SetBgmInput, T as ReplaceVideoClipSequenceInput, U as DeleteVideoClipsInput, V as moveSpeechesInputSchema, W as anchoredDeletePolicySchema, X as ChangeSpeechScriptInput, Y as deleteBgmInputSchema, Z as ChangeSpeechVoiceInput, _ as setVideoClipSpeedShiftInputSchema, a as speechAssetsSchema, at as adjustSpeechVolumeInputSchema, b as SetCaptionStyleInput, c as mediaIdSchema, ct as AddVideoClipsInput, d as speechIdsSchema, dt as addSpeechesInputSchema, et as AdjustVideoClipVolumeInput, f as speedShiftSchema, g as SetVideoClipSpeedShiftInput, h as volumeSchema, i as SpeechAssets, it as AdjustSpeechVolumeInput, j as moveVideoClipsInputSchema, k as replaceVideoClipContentInputSchema, l as positiveMsSchema, lt as addVideoClipsInputSchema, m as voiceSchema, n as CaptionAsset, nt as AdjustVideoClipDurationInput, o as clipIdSchema, ot as AdjustBgmVolumeInput, p as timelineMsSchema, q as deleteSpeechesInputSchema, r as SpeechAsset, rt as adjustVideoClipDurationInputSchema, s as clipIdsSchema, st as adjustBgmVolumeInputSchema, tt as adjustVideoClipVolumeInputSchema, u as speechIdSchema, ut as AddSpeechesInput, v as SetCaptionVisibilityInput, w as AnchoredReplacePolicy, x as setCaptionStyleInputSchema, y as setCaptionVisibilityInputSchema, z as moveBgmInputSchema } from "./index-CiDSfSMi.js";
2
- export { AddSpeechesInput, AddVideoClipsInput, AdjustBgmVolumeInput, AdjustSpeechVolumeInput, AdjustVideoClipDurationInput, AdjustVideoClipVolumeInput, AnchoredDeletePolicy, AnchoredReplacePolicy, CaptionAsset, ChangeSpeechScriptInput, ChangeSpeechVoiceInput, DeleteBgmInput, DeleteSpeechesInput, DeleteVideoClipsInput, MoveAnchor, MoveBgmInput, MoveSpeechesInput, MoveVideoClipsByAnchorInput, MoveVideoClipsInput, MovedClipAnchoredPolicy, ReplaceVideoClipContentInput, ReplaceVideoClipSequenceInput, SetBgmInput, SetCaptionStyleInput, SetCaptionVisibilityInput, SetVideoClipSpeedShiftInput, SpeechAsset, SpeechAssets, addSpeechesInputSchema, addVideoClipsInputSchema, adjustBgmVolumeInputSchema, adjustSpeechVolumeInputSchema, adjustVideoClipDurationInputSchema, adjustVideoClipVolumeInputSchema, anchoredDeletePolicySchema, anchoredReplacePolicySchema, changeSpeechScriptInputSchema, changeSpeechVoiceInputSchema, clipIdSchema, clipIdsSchema, deleteBgmInputSchema, deleteSpeechesInputSchema, deleteVideoClipsInputSchema, mediaIdSchema, moveAnchorSchema, moveBgmInputSchema, moveSpeechesInputSchema, moveVideoClipsByAnchorInputSchema, moveVideoClipsInputSchema, movedClipAnchoredPolicySchema, positiveMsSchema, replaceVideoClipContentInputSchema, replaceVideoClipSequenceInputSchema, setBgmInputSchema, setCaptionStyleInputSchema, setCaptionVisibilityInputSchema, setVideoClipSpeedShiftInputSchema, speechAssetsSchema, speechIdSchema, speechIdsSchema, speedShiftSchema, timelineMsSchema, voiceSchema, volumeSchema };
1
+ import { $ as adjustVideoClipVolumeInputSchema, A as MoveVideoClipsInput, B as AnchoredDeletePolicy, C as setBgmInputSchema, D as replaceVideoClipSequenceInputSchema, E as anchoredReplacePolicySchema, F as moveAnchorSchema, G as deleteSpeechesInputSchema, H as anchoredDeletePolicySchema, I as moveVideoClipsByAnchorInputSchema, J as ChangeSpeechScriptInput, K as DeleteBgmInput, L as movedClipAnchoredPolicySchema, M as MoveAnchor, N as MoveVideoClipsByAnchorInput, O as ReplaceVideoClipContentInput, P as MovedClipAnchoredPolicy, Q as AdjustVideoClipVolumeInput, R as MoveSpeechesInput, S as SetBgmInput, T as ReplaceVideoClipSequenceInput, U as deleteVideoClipsInputSchema, V as DeleteVideoClipsInput, W as DeleteSpeechesInput, X as changeSpeechScriptInputSchema, Y as ChangeSpeechVoiceInput, Z as changeSpeechVoiceInputSchema, _ as setVideoClipSpeedShiftInputSchema, a as speechAssetsSchema, at as adjustBgmVolumeInputSchema, b as SetCaptionStyleInput, c as mediaIdSchema, ct as AddSpeechesInput, d as speechIdsSchema, et as AdjustVideoClipDurationInput, f as speedShiftSchema, g as SetVideoClipSpeedShiftInput, h as volumeSchema, i as SpeechAssets, it as AdjustBgmVolumeInput, j as moveVideoClipsInputSchema, k as replaceVideoClipContentInputSchema, l as positiveMsSchema, lt as addSpeechesInputSchema, m as voiceSchema, n as CaptionAsset, nt as AdjustSpeechVolumeInput, o as clipIdSchema, ot as AddVideoClipsInput, p as timelineMsSchema, q as deleteBgmInputSchema, r as SpeechAsset, rt as adjustSpeechVolumeInputSchema, s as clipIdsSchema, st as addVideoClipsInputSchema, tt as adjustVideoClipDurationInputSchema, u as speechIdSchema, v as SetCaptionVisibilityInput, w as AnchoredReplacePolicy, x as setCaptionStyleInputSchema, y as setCaptionVisibilityInputSchema, z as moveSpeechesInputSchema } from "./index-InEWX9rk.js";
2
+ export { AddSpeechesInput, AddVideoClipsInput, AdjustBgmVolumeInput, AdjustSpeechVolumeInput, AdjustVideoClipDurationInput, AdjustVideoClipVolumeInput, AnchoredDeletePolicy, AnchoredReplacePolicy, CaptionAsset, ChangeSpeechScriptInput, ChangeSpeechVoiceInput, DeleteBgmInput, DeleteSpeechesInput, DeleteVideoClipsInput, MoveAnchor, MoveSpeechesInput, MoveVideoClipsByAnchorInput, MoveVideoClipsInput, MovedClipAnchoredPolicy, ReplaceVideoClipContentInput, ReplaceVideoClipSequenceInput, SetBgmInput, SetCaptionStyleInput, SetCaptionVisibilityInput, SetVideoClipSpeedShiftInput, SpeechAsset, SpeechAssets, addSpeechesInputSchema, addVideoClipsInputSchema, adjustBgmVolumeInputSchema, adjustSpeechVolumeInputSchema, adjustVideoClipDurationInputSchema, adjustVideoClipVolumeInputSchema, anchoredDeletePolicySchema, anchoredReplacePolicySchema, changeSpeechScriptInputSchema, changeSpeechVoiceInputSchema, clipIdSchema, clipIdsSchema, deleteBgmInputSchema, deleteSpeechesInputSchema, deleteVideoClipsInputSchema, mediaIdSchema, moveAnchorSchema, moveSpeechesInputSchema, moveVideoClipsByAnchorInputSchema, moveVideoClipsInputSchema, movedClipAnchoredPolicySchema, positiveMsSchema, replaceVideoClipContentInputSchema, replaceVideoClipSequenceInputSchema, setBgmInputSchema, setCaptionStyleInputSchema, setCaptionVisibilityInputSchema, setVideoClipSpeedShiftInputSchema, speechAssetsSchema, speechIdSchema, speechIdsSchema, speedShiftSchema, timelineMsSchema, voiceSchema, volumeSchema };
package/dist/schemas.js CHANGED
@@ -45,28 +45,24 @@ const voiceSchema = z.object({
45
45
  * stable speech + caption parts and writes them as authoritative facts. No
46
46
  * cascade runs on write — the projection derives absolute positions on read.
47
47
  *
48
- * `anchor_part_id` states the root relationship explicitly: a video/BGM id
49
- * creates an anchored speech; `null` creates an absolute audio root.
50
- * `offset_ms` is relative to the anchor or absolute for a root. Captions always
51
- * anchor to their speech via `start_ms`.
48
+ * Each speech carries the anchoring fact directly (RFC 02 §4): the host video
49
+ * clip `anchor_part_id` and the `offset_ms` within it. The upstream caller
50
+ * already knows which clip a speech attaches to, so the op writes
51
+ * `{ mode:'anchored', anchorPartId, offsetMs }` verbatim — no write-time
52
+ * host-picking. Captions anchor to their speech via the caption part's
53
+ * `start_ms` (offset within the speech).
52
54
  */
53
55
  const speechAssetSchema = z.object({
54
56
  speech_id: speechIdSchema.describe("The speech part ID (= side-effect speech_parts[].id)"),
55
- anchor_part_id: z.string().min(1).nullable().describe("Video/BGM parent part ID, or null when the speech itself is the root"),
56
- offset_ms: timelineMsSchema.describe("Relative offset from the parent, or absolute start for a root speech"),
57
+ anchor_part_id: clipIdSchema.describe("Host video clip part ID the speech anchors to (RFC 02 §4)"),
58
+ offset_ms: timelineMsSchema.describe("Offset within the host clip (speech.abs = host.abs + offset_ms)"),
57
59
  audio_storage_key: z.string().min(1),
58
60
  duration_ms: positiveMsSchema,
59
61
  audio_script: z.string(),
60
62
  volume: volumeSchema,
61
- voice: voiceSchema.optional(),
63
+ voice: voiceSchema,
62
64
  origin_speech_id: z.string().min(1),
63
65
  caption_ids: z.array(z.string().min(1)).describe("Caption part IDs owned by this speech")
64
- }).superRefine((speech, ctx) => {
65
- if (speech.audio_storage_key === speech.speech_id || speech.audio_storage_key === speech.origin_speech_id) ctx.addIssue({
66
- code: z.ZodIssueCode.custom,
67
- path: ["audio_storage_key"],
68
- message: "audio_storage_key must be the materialized storage key, not a speech id"
69
- });
70
66
  });
71
67
  const captionAssetSchema = z.object({
72
68
  caption_id: z.string().min(1).describe("The caption part ID (= side-effect created_caption_parts[].id)"),
@@ -79,21 +75,6 @@ const captionAssetSchema = z.object({
79
75
  const speechAssetsSchema = z.object({
80
76
  speeches: z.array(speechAssetSchema).min(1).describe("Materialized speech parts to write"),
81
77
  captions: z.array(captionAssetSchema).describe("Materialized caption parts owned by the speeches")
82
- }).superRefine((assets, ctx) => {
83
- const ownerByStorageKey = /* @__PURE__ */ new Map();
84
- for (const [index, speech] of assets.speeches.entries()) {
85
- const owner = ownerByStorageKey.get(speech.audio_storage_key);
86
- if (owner != null && owner !== speech.speech_id) ctx.addIssue({
87
- code: z.ZodIssueCode.custom,
88
- path: [
89
- "speeches",
90
- index,
91
- "audio_storage_key"
92
- ],
93
- message: "one materialized audio_storage_key must belong to one speech part"
94
- });
95
- ownerByStorageKey.set(speech.audio_storage_key, speech.speech_id);
96
- }
97
78
  });
98
79
  //#endregion
99
80
  //#region src/editor/schemas/add-speeches.ts
@@ -265,9 +246,6 @@ const moveSpeechesInputSchema = z.object({ speeches: z.array(z.object({
265
246
  new_start_ms: timelineMsSchema.describe("New absolute start time on the timeline")
266
247
  })).min(1).describe("Speeches to move to new positions") });
267
248
  //#endregion
268
- //#region src/editor/schemas/move-bgm.ts
269
- const moveBgmInputSchema = z.object({ new_start_ms: timelineMsSchema.describe("New absolute BGM start on the timeline") });
270
- //#endregion
271
249
  //#region src/editor/schemas/move-video-clips-by-anchor.ts
272
250
  /**
273
251
  * Where the moved block lands on the main track.
@@ -517,7 +495,6 @@ var schemas_exports = /* @__PURE__ */ __exportAll({
517
495
  deleteVideoClipsInputSchema: () => deleteVideoClipsInputSchema,
518
496
  mediaIdSchema: () => mediaIdSchema,
519
497
  moveAnchorSchema: () => moveAnchorSchema,
520
- moveBgmInputSchema: () => moveBgmInputSchema,
521
498
  moveSpeechesInputSchema: () => moveSpeechesInputSchema,
522
499
  moveVideoClipsByAnchorInputSchema: () => moveVideoClipsByAnchorInputSchema,
523
500
  moveVideoClipsInputSchema: () => moveVideoClipsInputSchema,
@@ -538,4 +515,4 @@ var schemas_exports = /* @__PURE__ */ __exportAll({
538
515
  volumeSchema: () => volumeSchema
539
516
  });
540
517
  //#endregion
541
- export { addSpeechesInputSchema, addVideoClipsInputSchema, adjustBgmVolumeInputSchema, adjustSpeechVolumeInputSchema, adjustVideoClipDurationInputSchema, adjustVideoClipVolumeInputSchema, anchoredDeletePolicySchema, anchoredReplacePolicySchema, changeSpeechScriptInputSchema, changeSpeechVoiceInputSchema, clipIdSchema, clipIdsSchema, deleteBgmInputSchema, deleteSpeechesInputSchema, deleteVideoClipsInputSchema, mediaIdSchema, moveAnchorSchema, moveBgmInputSchema, moveSpeechesInputSchema, moveVideoClipsByAnchorInputSchema, moveVideoClipsInputSchema, movedClipAnchoredPolicySchema, positiveMsSchema, replaceVideoClipContentInputSchema, replaceVideoClipSequenceInputSchema, setBgmInputSchema, setCaptionStyleInputSchema, setCaptionVisibilityInputSchema, setVideoClipSpeedShiftInputSchema, speechAssetsSchema, speechIdSchema, speechIdsSchema, speedShiftSchema, schemas_exports as t, timelineMsSchema, voiceSchema, volumeSchema };
518
+ export { addSpeechesInputSchema, addVideoClipsInputSchema, adjustBgmVolumeInputSchema, adjustSpeechVolumeInputSchema, adjustVideoClipDurationInputSchema, adjustVideoClipVolumeInputSchema, anchoredDeletePolicySchema, anchoredReplacePolicySchema, changeSpeechScriptInputSchema, changeSpeechVoiceInputSchema, clipIdSchema, clipIdsSchema, deleteBgmInputSchema, deleteSpeechesInputSchema, deleteVideoClipsInputSchema, mediaIdSchema, moveAnchorSchema, moveSpeechesInputSchema, moveVideoClipsByAnchorInputSchema, moveVideoClipsInputSchema, movedClipAnchoredPolicySchema, positiveMsSchema, replaceVideoClipContentInputSchema, replaceVideoClipSequenceInputSchema, setBgmInputSchema, setCaptionStyleInputSchema, setCaptionVisibilityInputSchema, setVideoClipSpeedShiftInputSchema, speechAssetsSchema, speechIdSchema, speechIdsSchema, speedShiftSchema, schemas_exports as t, timelineMsSchema, voiceSchema, volumeSchema };
package/dist/testing.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { c as MirrorVideoDocumentAdapter, ct as VideoDraft } from "./index-DkJ0JK2t.js";
1
+ import { c as MirrorVideoDocumentAdapter, ct as VideoDraft } from "./index-BO2fSUKi.js";
2
2
 
3
3
  //#region src/testing/in-memory-mengine-server.d.ts
4
4
  /**
package/dist/testing.js CHANGED
@@ -1,4 +1,4 @@
1
- import { G as base64ToBytes, K as bytesToBase64, o as createMirrorVideoDocumentAdapter, z as VIDEO_DOCUMENT_SCHEMA_VERSION } from "./document-C-h5-rCG.js";
1
+ import { L as VIDEO_DOCUMENT_SCHEMA_VERSION, U as base64ToBytes, W as bytesToBase64, o as createMirrorVideoDocumentAdapter } from "./document-49OdvviW.js";
2
2
  import { t as classifyUpdate } from "./loro-relay-doc-ssdYpuef.js";
3
3
  import { LoroDoc, VersionVector, encodeFrontiers } from "loro-crdt";
4
4
  //#region src/testing/in-memory-mengine-server.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mengine/medeo-client",
3
- "version": "1.2.1-alpha.4",
3
+ "version": "1.2.1-alpha.6",
4
4
  "license": "UNLICENSED",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,9 +27,9 @@
27
27
  "immer": "^10.2.0",
28
28
  "loro-mirror": "^2.2.0",
29
29
  "zod": "^4.4.3",
30
- "@mengine/storage": "1.2.1-alpha.4",
31
- "@mengine/utils": "1.2.1-alpha.4",
32
- "@mengine/sync": "1.2.1-alpha.4"
30
+ "@mengine/sync": "1.2.1-alpha.6",
31
+ "@mengine/utils": "1.2.1-alpha.6",
32
+ "@mengine/storage": "1.2.1-alpha.6"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/node": "^25.9.1",