@mengine/medeo-client 1.0.1-alpha.2 → 1.1.0

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.
@@ -1,7 +1,6 @@
1
1
  import { Mirror, schema } from "loro-mirror";
2
2
  import { z } from "zod";
3
3
  import { LoroDoc } from "loro-crdt";
4
- import { produce } from "immer";
5
4
  //#region src/client/base64.ts
6
5
  function bytesToBase64(bytes) {
7
6
  let binary = "";
@@ -536,7 +535,12 @@ function cascadeAfterVideoClipChanges(doc, makeEmptyPart) {
536
535
  function solveVideoDocument(document) {
537
536
  const doc = videoDocumentToTimelineDoc(document);
538
537
  let counter = 0;
539
- cascadeAfterVideoClipChanges(doc, () => ({ partId: `empty_${counter++}` }));
538
+ const derivedFillerPartIds = /* @__PURE__ */ new Set();
539
+ cascadeAfterVideoClipChanges(doc, () => {
540
+ const partId = `empty_${counter++}`;
541
+ derivedFillerPartIds.add(partId);
542
+ return { partId };
543
+ });
540
544
  const absByPartId = /* @__PURE__ */ new Map();
541
545
  for (const item of doc.main_track) absByPartId.set(item.part_id, item.abs_time_position);
542
546
  for (const item of doc.speech_track) absByPartId.set(item.part_id, item.abs_time_position);
@@ -552,7 +556,8 @@ function solveVideoDocument(document) {
552
556
  }))
553
557
  })),
554
558
  durationMs: doc.timeline.duration_ms,
555
- partLibrary: doc.part_library
559
+ partLibrary: doc.part_library,
560
+ derivedFillerPartIds
556
561
  };
557
562
  }
558
563
  function videoDocumentToTimelineDoc(document) {
@@ -643,6 +648,42 @@ function seedAggregations(mainItems, speechItems) {
643
648
  return order.map((host) => byHost.get(host));
644
649
  }
645
650
  /**
651
+ * The four lanes in top-to-bottom stack order — the order a `tracks` list holds
652
+ * them in (see {@link laneRank}).
653
+ *
654
+ * Exported so a document can be seeded with all four lanes up front. That seed is
655
+ * not cosmetic: {@link ensureLaneTrack} is find-then-mint over a `LoroMovableList`,
656
+ * so two concurrent writers that each mint the same absent lane both keep their
657
+ * row, and the merged document holds two tracks for one lane. For the main lane
658
+ * that is fatal — `videoDocumentSchema` allows at most one `video_clip` track, so
659
+ * the merged document stops being projectable at all, symmetrically on both
660
+ * replicas. Pre-seeding every lane makes `ensureLaneTrack` always take its find
661
+ * branch, which removes the race by construction rather than by detection.
662
+ *
663
+ * What closes the race is that a track with the lane's `parts_kind` EXISTS — the
664
+ * lookup is by kind, not by id. So a seed is only safe if it covers every lane:
665
+ * a partial seed leaves the uncovered lanes exactly as exposed as before.
666
+ */
667
+ const LANE_KINDS_IN_STACK_ORDER = [
668
+ "caption",
669
+ "video_clip",
670
+ "speech",
671
+ "bgm"
672
+ ];
673
+ /**
674
+ * The conventional track id for a lane (`main_track`, `<kind>_track`). Shared by
675
+ * the up-front seed and {@link ensureLaneTrack}'s lazy mint so a document's lane
676
+ * ids do not depend on which of the two created the track.
677
+ *
678
+ * Ids are cosmetic to the merge itself — lane lookup goes by `parts_kind`, so
679
+ * drifting them apart would not reopen the concurrent-mint race. They matter to
680
+ * readers that address a lane by id (the FE editor's panes, fixtures), which is
681
+ * why there is one convention rather than two.
682
+ */
683
+ function laneTrackId(kind) {
684
+ return kind === "video_clip" ? "main_track" : `${kind}_track`;
685
+ }
686
+ /**
646
687
  * Lane-stacking rank for the single `tracks` list (reference/17 §4): caption
647
688
  * (above) sits before the video_clip main track, which sits before speech / bgm
648
689
  * (below). The `tracks` array is kept in this top-to-bottom order so a freshly
@@ -673,14 +714,18 @@ function insertTrackByLaneOrder(tracks, track) {
673
714
  * Locate a lane's track row in the single `tracks` list by kind, minting an empty
674
715
  * row in lane-stacking order if absent (reference/17 §4: lane = `parts_kind`).
675
716
  * Ops use this to write authoritative items onto the right lane. The track id
676
- * mirrors the seed convention (`<kind>_track`).
717
+ * comes from {@link laneTrackId}, shared with the up-front seed.
718
+ *
719
+ * The mint branch is a concurrency hazard, not a convenience: see
720
+ * {@link LANE_KINDS_IN_STACK_ORDER}. A document seeded with all four lanes never
721
+ * reaches it.
677
722
  */
678
723
  function ensureLaneTrack(draft, kind) {
679
724
  draft.tracks ??= [];
680
725
  let track = draft.tracks.find((t) => t?.parts_kind === kind);
681
726
  if (track == null) {
682
727
  track = {
683
- id: kind === "video_clip" ? "main_track" : `${kind}_track`,
728
+ id: laneTrackId(kind),
684
729
  parts_kind: kind,
685
730
  is_hidden: void 0,
686
731
  items: []
@@ -876,11 +921,59 @@ function validateVideoDocument(document) {
876
921
  validatePartValues(partId, part, issues);
877
922
  }
878
923
  for (const [idx, track] of (doc.tracks ?? []).entries()) validateTrack(track, `tracks/${idx}`, partLibrary, issues, track.parts_kind === "video_clip");
924
+ validateLaneTrackUniqueness(doc, issues);
879
925
  validateSpeechCaptionReferences(partLibrary, issues);
880
926
  validatePositionReferences(doc, partLibrary, issues);
881
927
  return issues;
882
928
  }
883
929
  /**
930
+ * Report a duplicated lane: two tracks sharing the same `id`, or two secondary
931
+ * tracks of the same `parts_kind`.
932
+ *
933
+ * Found by the Phase 6 M0/S2 concurrency probe. `ensureLaneTrack` locates a lane
934
+ * by `parts_kind` and mints `<kind>_track` when absent, so two replicas that both
935
+ * start without (say) a caption track each create one; `tracks` is a
936
+ * `LoroMovableList`, so the merge keeps BOTH. The lane is then split across two
937
+ * same-id tracks, and the projection's `find`-by-kind returns only one of them —
938
+ * so an item can be authoritative yet invisible in the pane a reader looks at.
939
+ *
940
+ * Flagged **recoverable**, not `error`, for two reasons. It is a reachable
941
+ * outcome of ordinary concurrent editing, and hard-rejecting would make an
942
+ * unavoidable merge result un-projectable — the same argument §11.1 makes for
943
+ * orphans. And the projection already tolerates it: `solveVideoDocument`
944
+ * concatenates every track of a kind, so the cascade sees all items regardless.
945
+ * The defect is a *reader-visible* split, so the right response is to surface it
946
+ * (loudly, in a channel someone reads), not to block the document.
947
+ *
948
+ * The main track is exempt from the kind check: `parts_kind === 'video_clip'` may
949
+ * legitimately appear on several tracks (the projection treats only the first as
950
+ * the main pane), so only its `id` collision is reported.
951
+ */
952
+ function validateLaneTrackUniqueness(doc, issues) {
953
+ const tracks = doc.tracks ?? [];
954
+ const seenIds = /* @__PURE__ */ new Set();
955
+ const seenSecondaryKinds = /* @__PURE__ */ new Set();
956
+ for (const [idx, track] of tracks.entries()) {
957
+ const id = track?.id;
958
+ if (id != null && id !== "") if (seenIds.has(id)) issues.push({
959
+ code: "duplicate_lane_track",
960
+ path: `/tracks/${idx}/id`,
961
+ message: `Track "tracks/${idx}" reuses track id "${id}"`,
962
+ severity: "recoverable"
963
+ });
964
+ else seenIds.add(id);
965
+ const kind = track?.parts_kind;
966
+ if (kind == null || kind === "video_clip") continue;
967
+ if (seenSecondaryKinds.has(kind)) issues.push({
968
+ code: "duplicate_lane_track",
969
+ path: `/tracks/${idx}/parts_kind`,
970
+ message: `Lane "${kind}" is split across more than one track (at "tracks/${idx}")`,
971
+ severity: "recoverable"
972
+ });
973
+ else seenSecondaryKinds.add(kind);
974
+ }
975
+ }
976
+ /**
884
977
  * An `anchored` item whose `anchorPartId` no longer exists in the library is the
885
978
  * orphan condition (RFC 02 §4/§11.1) — e.g. a speech whose host video, or a
886
979
  * caption whose host speech, was concurrently deleted while this item was being
@@ -1102,7 +1195,7 @@ function toAuthoritativePartLibrary(partLibrary) {
1102
1195
  const { duration_ms, rest } = splitDurationMs(part.caption);
1103
1196
  out[partId] = { caption: {
1104
1197
  ...rest,
1105
- initial_duration_ms: duration_ms
1198
+ initial_duration_ms: rest.initial_duration_ms ?? duration_ms
1106
1199
  } };
1107
1200
  } else if (part.bgm != null) out[partId] = { bgm: omitDurationMs(part.bgm) };
1108
1201
  }
@@ -1209,7 +1302,7 @@ function fromVideoDocument(document) {
1209
1302
  above_main_tracks: aboveTracks.map((t) => draftTrack(t, view.absByPartId)),
1210
1303
  below_main_tracks: belowTracks.map((t) => draftTrack(t, view.absByPartId)),
1211
1304
  part_aggregations: view.aggregations,
1212
- part_library: toReadViewPartLibrary(view.partLibrary, view.durationMs),
1305
+ part_library: toReadViewPartLibrary(view.partLibrary, view.durationMs, view.derivedFillerPartIds),
1213
1306
  version: document.meta.version
1214
1307
  };
1215
1308
  }
@@ -1225,31 +1318,38 @@ function fromVideoDocument(document) {
1225
1318
  *
1226
1319
  * Parts are deep-cloned; the engine extensions (`media_duration_ms`,
1227
1320
  * `initial_duration_ms`) are kept alongside the injected `duration_ms`.
1321
+ *
1322
+ * `derivedFillerPartIds` are skipped: the solve minted them to lay the track out
1323
+ * and they are not part of the document (see `fromVideoDocument`). An empty clip a
1324
+ * writer placed deliberately is NOT in that set and is projected normally.
1228
1325
  */
1229
- function toReadViewPartLibrary(partLibrary, durationMs) {
1326
+ function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds) {
1230
1327
  const out = {};
1231
- for (const [partId, part] of Object.entries(partLibrary)) if (part.video_clip != null) {
1232
- const clip = clone(part.video_clip);
1233
- out[partId] = { video_clip: {
1234
- ...clip,
1235
- duration_ms: effectiveVideoClipDurationMs(clip)
1236
- } };
1237
- } else if (part.speech != null) {
1238
- const speech = clone(part.speech);
1239
- out[partId] = { speech: {
1240
- ...speech,
1241
- duration_ms: speech.media_duration_ms
1242
- } };
1243
- } else if (part.caption != null) {
1244
- const caption = clone(part.caption);
1245
- out[partId] = { caption: {
1246
- ...caption,
1247
- duration_ms: caption.initial_duration_ms
1328
+ for (const [partId, part] of Object.entries(partLibrary)) {
1329
+ if (derivedFillerPartIds.has(partId)) continue;
1330
+ if (part.video_clip != null) {
1331
+ const clip = clone(part.video_clip);
1332
+ out[partId] = { video_clip: {
1333
+ ...clip,
1334
+ duration_ms: effectiveVideoClipDurationMs(clip)
1335
+ } };
1336
+ } else if (part.speech != null) {
1337
+ const speech = clone(part.speech);
1338
+ out[partId] = { speech: {
1339
+ ...speech,
1340
+ duration_ms: speech.media_duration_ms
1341
+ } };
1342
+ } else if (part.caption != null) {
1343
+ const caption = clone(part.caption);
1344
+ out[partId] = { caption: {
1345
+ ...caption,
1346
+ duration_ms: caption.initial_duration_ms
1347
+ } };
1348
+ } else if (part.bgm != null) out[partId] = { bgm: {
1349
+ ...clone(part.bgm),
1350
+ duration_ms: durationMs
1248
1351
  } };
1249
- } else if (part.bgm != null) out[partId] = { bgm: {
1250
- ...clone(part.bgm),
1251
- duration_ms: durationMs
1252
- } };
1352
+ }
1253
1353
  return out;
1254
1354
  }
1255
1355
  /** Deep-clone a part payload, dropping the derived read-view `duration_ms`. */
@@ -1307,6 +1407,57 @@ function clone(value) {
1307
1407
  return value;
1308
1408
  }
1309
1409
  //#endregion
1410
+ //#region src/document/initial-document.ts
1411
+ /**
1412
+ * Build the `VideoDocument` a newly created project starts from: the caller's
1413
+ * project facts, no parts, and one empty track per lane.
1414
+ *
1415
+ * The empty lane tracks are the reason this function exists rather than callers
1416
+ * assembling a document inline. Lane tracks are otherwise minted lazily by the
1417
+ * first op that needs one (`ensureLaneTrack`), which is find-then-mint over a
1418
+ * CRDT list — so if the Agent's first generation and a user edit race on an
1419
+ * empty document, each mints its own copy of the same lane and the merge keeps
1420
+ * both. Two video_clip tracks violate the at-most-one-main-track rule, and the
1421
+ * merged document becomes unprojectable for *every* reader (editor, render,
1422
+ * share) with no winning replica to fall back on. Seeding all four lanes up
1423
+ * front means `ensureLaneTrack` only ever finds, never mints, so the race cannot
1424
+ * happen on a document created here.
1425
+ *
1426
+ * All four, not just the main lane: the secondary lanes fail less loudly (a
1427
+ * duplicate pane rather than an unreadable document), but they fail by the same
1428
+ * mechanism, and covering only the fatal one would leave three live races.
1429
+ *
1430
+ * `timeline` is left absent: `unit_time_ms` is a display concern the editor
1431
+ * supplies, and total duration is derived on read (RFC 02 §6), so a new document
1432
+ * has no timeline fact to state.
1433
+ */
1434
+ function buildInitialVideoDocument(facts) {
1435
+ return {
1436
+ meta: {
1437
+ schema_version: VIDEO_DOCUMENT_SCHEMA_VERSION,
1438
+ draft_id: facts.draftId,
1439
+ project_id: facts.projectId,
1440
+ owner_id: facts.ownerId,
1441
+ thumbnail_storage_key: void 0,
1442
+ chat_session_id: facts.chatSessionId,
1443
+ video_creation_settings: facts.videoCreationSettings,
1444
+ version: void 0
1445
+ },
1446
+ timeline: void 0,
1447
+ tracks: emptyLaneTracks(),
1448
+ part_library: {}
1449
+ };
1450
+ }
1451
+ /** One empty track per lane, in lane-stacking order, with the conventional ids. */
1452
+ function emptyLaneTracks() {
1453
+ return LANE_KINDS_IN_STACK_ORDER.map((kind) => ({
1454
+ id: laneTrackId(kind),
1455
+ parts_kind: kind,
1456
+ is_hidden: void 0,
1457
+ items: []
1458
+ }));
1459
+ }
1460
+ //#endregion
1310
1461
  //#region src/document/mirror-read.ts
1311
1462
  /**
1312
1463
  * Project the mirror state (`VideoDocumentDraft`) into the authoritative
@@ -1422,7 +1573,8 @@ var MirrorVideoDocumentAdapter = class {
1422
1573
  message: JSON.stringify({
1423
1574
  semantic_op: audit.kind,
1424
1575
  payload: audit.payload,
1425
- intent: audit.intent ?? null
1576
+ intent: audit.intent ?? null,
1577
+ actor: audit.actor ?? null
1426
1578
  })
1427
1579
  });
1428
1580
  }
@@ -1436,7 +1588,7 @@ function createMirrorVideoDocument(document, options = {}) {
1436
1588
  doc,
1437
1589
  schema: videoDocumentMirrorSchema
1438
1590
  }).setState((draft) => {
1439
- writeVideoDocumentToDraft(draft, document);
1591
+ seedDraft(draft, document);
1440
1592
  }, { origin: options.origin ?? "mengine.bootstrap" });
1441
1593
  return doc;
1442
1594
  }
@@ -1444,8 +1596,8 @@ function createMirrorVideoDocument(document, options = {}) {
1444
1596
  function createMirrorVideoDocumentAdapter(document, options) {
1445
1597
  return new MirrorVideoDocumentAdapter(createMirrorVideoDocument(document, options));
1446
1598
  }
1447
- /** Write a whole `VideoDocument` into a draft (seed a fresh doc / plain-memory state). */
1448
- function writeVideoDocumentToDraft(draft, document) {
1599
+ /** Write a whole `VideoDocument` into the mirror draft (used to seed a fresh doc). */
1600
+ function seedDraft(draft, document) {
1449
1601
  draft.meta = {
1450
1602
  schema_version: document.meta.schema_version,
1451
1603
  draft_id: document.meta.draft_id ?? void 0,
@@ -1475,119 +1627,4 @@ function toTrackRow(track) {
1475
1627
  };
1476
1628
  }
1477
1629
  //#endregion
1478
- //#region src/editor/id-gen.ts
1479
- /**
1480
- * Part-id generation, aligned with the online ecosystem.
1481
- *
1482
- * The authoritative online producers — agent-harness (`@harness/shared`
1483
- * `genObjId`) and director.v2 (`common/obj_id.py` `gen_obj_id`) — both mint part
1484
- * ids as `` `${prefix}_${ulid()}` ``, and real captured drafts use exactly that
1485
- * shape (`clip_…` / `spe_…` / `cap_…` / `bgm_…`, each a 26-char ULID). The engine
1486
- * previously emitted `vc_<base36 timestamp><6 random>`, a different prefix AND a
1487
- * different encoding — the sole cross-repo id divergence. This module removes it
1488
- * by emitting the same `<prefix>_<ULID>` bytes.
1489
- *
1490
- * The ULID is generated inline (Crockford Base32, 48-bit time + 80-bit random)
1491
- * rather than pulling the `ulid` npm package: the randomness class matches the
1492
- * old generator (both `Math.random`-based) and it keeps `@mengine/medeo-client`
1493
- * dependency-free for a purely mechanical id string. Part ids only need to be
1494
- * unique and lexicographically time-sortable, which this satisfies.
1495
- */
1496
- /** Crockford Base32 alphabet (no I, L, O, U), per the ULID spec. */
1497
- const CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
1498
- const TIME_LEN = 10;
1499
- const RANDOM_LEN = 16;
1500
- function encodeTime(now) {
1501
- let out = "";
1502
- let ms = now;
1503
- for (let i = TIME_LEN - 1; i >= 0; i--) {
1504
- const mod = ms % 32;
1505
- out = CROCKFORD[mod] + out;
1506
- ms = (ms - mod) / 32;
1507
- }
1508
- return out;
1509
- }
1510
- function encodeRandom() {
1511
- let out = "";
1512
- for (let i = 0; i < RANDOM_LEN; i++) out += CROCKFORD[Math.floor(Math.random() * 32)];
1513
- return out;
1514
- }
1515
- /** A 26-char Crockford Base32 ULID (10-char time + 16-char random). */
1516
- function ulid() {
1517
- return encodeTime(Date.now()) + encodeRandom();
1518
- }
1519
- function generatePartId(prefix) {
1520
- return `${prefix}_${ulid()}`;
1521
- }
1522
- //#endregion
1523
- //#region src/document/plain-memory-adapter.ts
1524
- /**
1525
- * Pure in-memory `SemanticDocumentAdapter` — no Loro/WASM. Holds a
1526
- * `VideoDocumentDraft` object and applies each `transact` via immer `produce`,
1527
- * journaling every audit that actually mutated state (plus any ids minted
1528
- * during that transact).
1529
- *
1530
- * Known benign difference vs `MirrorVideoDocumentAdapter`: the editor's
1531
- * `setPart` assigns a fresh part object on every call, so a same-value rewrite
1532
- * produces a new immer state and IS journaled here, while the mirror's deep
1533
- * diff emits no commit. Terminal `snapshot()` stays equal; replay is idempotent.
1534
- */
1535
- var PlainMemoryAdapter = class {
1536
- state;
1537
- _journal = [];
1538
- baseIdFactory;
1539
- /** Non-null only while a `transact` edit callback is running. */
1540
- pendingIds = null;
1541
- /**
1542
- * Recording wrapper around the underlying factory. Callers (sandbox editor)
1543
- * use this so every minted id is appended to the current transact's list.
1544
- */
1545
- idFactory;
1546
- constructor(document, options) {
1547
- assertValidVideoDocument(document);
1548
- const draft = {};
1549
- writeVideoDocumentToDraft(draft, document);
1550
- this.state = draft;
1551
- this.baseIdFactory = options?.idFactory ?? generatePartId;
1552
- this.idFactory = (prefix) => {
1553
- const id = this.baseIdFactory(prefix);
1554
- if (this.pendingIds != null) this.pendingIds.push(id);
1555
- return id;
1556
- };
1557
- }
1558
- get journal() {
1559
- return this._journal;
1560
- }
1561
- hasContent() {
1562
- return (this.state.meta?.schema_version ?? "") !== "";
1563
- }
1564
- snapshot() {
1565
- return readVideoDocumentFromDraft(this.state);
1566
- }
1567
- /**
1568
- * Apply one op via immer. A throw in `edit` discards the draft (state and
1569
- * journal unchanged). When `produce` returns the same reference, there was
1570
- * no structural change — skip journal, matching mirror "no change, no commit".
1571
- */
1572
- transact(edit, audit) {
1573
- this.pendingIds = [];
1574
- try {
1575
- const next = produce(this.state, edit);
1576
- if (next !== this.state) {
1577
- this.state = next;
1578
- this._journal.push({
1579
- ...audit,
1580
- generated_ids: this.pendingIds
1581
- });
1582
- }
1583
- } finally {
1584
- this.pendingIds = null;
1585
- }
1586
- }
1587
- };
1588
- /** Build a `PlainMemoryAdapter` seeded with `document`. */
1589
- function createPlainMemoryAdapter(document, options) {
1590
- return new PlainMemoryAdapter(document, options);
1591
- }
1592
- //#endregion
1593
- export { isEmptyVideoClip as A, bytesToBase64 as B, fillMainTrackTimeGaps as C, resolveSpeechOverlapByShiftingVideos as D, resolveAllSpeechOverlaps as E, speedOf as F, partUnionToDraft as I, recordEntries as L, safeDurationMs as M, VIDEO_DOCUMENT_SCHEMA_VERSION as N, syncAggregatedClipsTimePosition as O, effectiveVideoClipDurationMs as P, videoDocumentMirrorSchema as R, arrangeMainTrackSeamlessly as S, recalculateTimelineDuration as T, videoDocumentSchema as _, createMirrorVideoDocument as a, solveVideoDocument as b, readVideoDocumentFromDraft as c, fromVideoDocument as d, toVideoDocument as f, partUnionSchema as g, validateVideoDocument as h, MirrorVideoDocumentAdapter as i, partDurationMs as j, TIMELINE_SKELETON_DURATION_MS as k, buildSpeechHostMap as l, assertValidVideoDocument as m, createPlainMemoryAdapter as n, createMirrorVideoDocumentAdapter as o, VideoDocumentValidationError as p, generatePartId as r, writeVideoDocumentToDraft as s, PlainMemoryAdapter as t, derivePositionFromAbs as u, ensureLaneTrack as v, reassignSpeechesToVideoClipsByTime as w, cascadeAfterVideoClipChanges as x, findLaneTrack as y, base64ToBytes as z };
1630
+ export { partDurationMs as A, reassignSpeechesToVideoClipsByTime as C, syncAggregatedClipsTimePosition as D, resolveSpeechOverlapByShiftingVideos as E, recordEntries as F, videoDocumentMirrorSchema as I, base64ToBytes as L, VIDEO_DOCUMENT_SCHEMA_VERSION as M, effectiveVideoClipDurationMs as N, TIMELINE_SKELETON_DURATION_MS as O, partUnionToDraft as P, bytesToBase64 as R, fillMainTrackTimeGaps as S, resolveAllSpeechOverlaps as T, findLaneTrack as _, buildInitialVideoDocument as a, cascadeAfterVideoClipChanges as b, fromVideoDocument as c, assertValidVideoDocument as d, validateVideoDocument as f, ensureLaneTrack as g, LANE_KINDS_IN_STACK_ORDER as h, readVideoDocumentFromDraft as i, safeDurationMs as j, isEmptyVideoClip as k, toVideoDocument as l, videoDocumentSchema as m, createMirrorVideoDocument as n, buildSpeechHostMap as o, partUnionSchema as p, createMirrorVideoDocumentAdapter as r, derivePositionFromAbs as s, MirrorVideoDocumentAdapter as t, VideoDocumentValidationError as u, laneTrackId as v, recalculateTimelineDuration as w, arrangeMainTrackSeamlessly as x, solveVideoDocument as y };