@mengine/medeo-client 1.3.1-alpha.0 → 1.3.1-alpha.1

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.
package/README.md CHANGED
@@ -44,8 +44,7 @@ boundary already fails rows whose media variants lack `external` or carry a
44
44
  media is an explicit caller decision, and no implicit historical merge or
45
45
  identity rewriting occurs. The
46
46
  compatibility reader reads physical facts directly from the media variant;
47
- Caption inline text still resolves its inline Asset through
48
- `physical-asset`.
47
+ Caption text is assembled from its required AudioScript composition and never stored in an inline Asset.
49
48
 
50
49
  `SequenceMarker` owns source/target ranges, duration, and time remapping. `Clip`
51
50
  owns clip properties such as volume; `Track` owns track properties. References
@@ -74,15 +73,26 @@ their follow, keep-absolute, cascade, or detach decisions into the same entity
74
73
  plan. A speech-overlap shift is explicit placement on the real visual Clips;
75
74
  an uncovered time interval does not require an invented empty-media entity.
76
75
 
77
- Voice links to its AudioScript through `audio-script-render`; Caption links to
78
- its source script and optional alignment Voice through separate provenance/alignment relations. External
79
- speech identity and physical storage key belong to the Voice Entity itself.
80
- `insertCaptionClip` creates a complete independent Caption placement;
81
- `upsertVoiceoverTake` accepts explicit `placement` for independent voice.
82
- AudioScript carries only text. `audio-script-marker` attaches directly assigned
83
- `segmentRanges` timing; those annotation Markers cannot be Clip display Markers.
84
- Caption styles belong to Caption; text can have a real inline text Asset rather
85
- than a fabricated Memota ID. Background Audio's Marker declares
76
+ Generated Voice links to a pre-existing PhoneticScript through `phonetic-script-render`.
77
+ Caption and PhoneticScript each compose a real AudioScript through exactly one
78
+ `caption-composition` or `phonetic-script-composition` relation. AudioScript owns
79
+ `segments[].text`; the variants never persist a text copy. Read complete content
80
+ with `assembleCaptionContent` or `assemblePhoneticScriptContent`. Broken composition
81
+ fails explicitly. Recorded Audio/Video/Voice can be the ASR source via
82
+ `audio-script-source`, without creating a synthesis variant.
83
+
84
+ `insertCaptionClip` requires `audioScriptEntityId` and `selections`. Each selection
85
+ names a source `segmentId` and optionally a half-open Unicode code-point
86
+ `textRange: {start, end}`. This permits display re-segmentation without rewriting
87
+ the original script. `upsertVoiceoverTake` requires the real
88
+ `phoneticScriptEntityId` used for synthesis; its captions select the same script.
89
+ External speech identity and storage key stay on Voice.
90
+
91
+ AudioScript has no intrinsic Sequence and cannot enter a Clip. `audio-script-marker`
92
+ attaches directly assigned `segmentRanges` timing; annotation Markers never refer
93
+ to upstream Markers and cannot be Clip display Markers. Moving or aligning a
94
+ Caption changes its external display Marker, preserving intrinsic Caption extent.
95
+ Caption owns its styles and text selection. Background Audio's Marker declares
86
96
  `durationPolicy: 'timeline'`: its source duration stays factual,
87
97
  while the view fills the non-BGM timeline duration.
88
98
 
@@ -1524,6 +1524,123 @@ function isRecord$1(value) {
1524
1524
  return typeof value === "object" && value != null && !Array.isArray(value);
1525
1525
  }
1526
1526
  //#endregion
1527
+ //#region ../medeo-dsl/src/composition.ts
1528
+ /**
1529
+ * Raised when a variant's complete content cannot be assembled from its
1530
+ * required composition Relation. Assembly never falls back to variant-local
1531
+ * text: a missing, ambiguous, or dangling source is an error, not an empty
1532
+ * read.
1533
+ */
1534
+ var ScriptCompositionError = class extends Error {
1535
+ code;
1536
+ entityId;
1537
+ constructor(code, entityId, message) {
1538
+ super(message);
1539
+ this.code = code;
1540
+ this.entityId = entityId;
1541
+ this.name = "ScriptCompositionError";
1542
+ }
1543
+ };
1544
+ function compositionRelationKind(variantKind) {
1545
+ return variantKind === "caption" ? "caption-composition" : "phonetic-script-composition";
1546
+ }
1547
+ /**
1548
+ * Resolve the one AudioScript a variant composes. Relations are queried from
1549
+ * both endpoints, so persisted endpoint positions do not matter.
1550
+ */
1551
+ function findComposedAudioScript(rows, variantEntityId, variantKind) {
1552
+ const kind = compositionRelationKind(variantKind);
1553
+ const edges = rows.relations.filter((relation) => relation.relationKind === kind && (relation.endpoint0EntityId === variantEntityId || relation.endpoint1EntityId === variantEntityId));
1554
+ if (edges.length === 0) throw new ScriptCompositionError("composition_missing", variantEntityId, `${variantKind} "${variantEntityId}" has no ${kind} Relation; it has no content without its AudioScript`);
1555
+ if (edges.length > 1) throw new ScriptCompositionError("composition_ambiguous", variantEntityId, `${variantKind} "${variantEntityId}" has ${edges.length} ${kind} Relations; exactly one AudioScript is required`);
1556
+ const edge = edges[0];
1557
+ const otherId = edge.endpoint0EntityId === variantEntityId ? edge.endpoint1EntityId : edge.endpoint0EntityId;
1558
+ const script = rows.entities.find((entity) => entity.entityId === otherId);
1559
+ if (script === void 0 || script.entityKind !== "audio-script") throw new ScriptCompositionError("composition_dangling", variantEntityId, `${variantKind} "${variantEntityId}" ${kind} Relation must resolve a live AudioScript, got "${script?.entityKind ?? "missing entity"}"`);
1560
+ return script;
1561
+ }
1562
+ /** Join the whole AudioScript text in segment order. */
1563
+ function assembleScriptText(script) {
1564
+ return scriptSegments(script).map((segment) => segment.text).join("");
1565
+ }
1566
+ function scriptSegments(script) {
1567
+ const segments = script.payload.segments;
1568
+ if (!Array.isArray(segments)) throw new ScriptCompositionError("composition_dangling", script.entityId, `AudioScript "${script.entityId}" requires segments`);
1569
+ if (!segments.every(isScriptSegment) || new Set(segments.map((s) => s.segmentId)).size !== segments.length) throw new ScriptCompositionError("invalid_script", script.entityId, "AudioScript requires valid segments with unique local segmentId and text");
1570
+ return segments;
1571
+ }
1572
+ function isScriptSegment(value) {
1573
+ if (typeof value !== "object" || value == null || Array.isArray(value)) return false;
1574
+ const segment = value;
1575
+ return typeof segment.segmentId === "string" && segment.segmentId.trim() !== "" && typeof segment.text === "string" && (segment.language === void 0 || typeof segment.language === "string");
1576
+ }
1577
+ /**
1578
+ * Assemble the complete Caption content from its AudioScript: the selected
1579
+ * segments in selection order, joined as display text. The Caption payload
1580
+ * never carries text, so a broken composition fails here instead of silently
1581
+ * rendering an empty caption.
1582
+ */
1583
+ function assembleCaptionContent(rows, captionEntityId) {
1584
+ const caption = requireEntityKind(rows, captionEntityId, "caption");
1585
+ const script = findComposedAudioScript(rows, captionEntityId, "caption");
1586
+ const segments = selectAudioScriptSegments(script, captionSelections(caption));
1587
+ return {
1588
+ caption,
1589
+ audioScript: script,
1590
+ segments,
1591
+ text: segments.map((segment) => segment.text).join("")
1592
+ };
1593
+ }
1594
+ /**
1595
+ * Assemble the complete Phonetic Script content for TTS: the composed
1596
+ * AudioScript's base text plus the variant's own phoneme and prosody fields.
1597
+ */
1598
+ function assemblePhoneticScriptContent(rows, phoneticScriptEntityId) {
1599
+ const phoneticScript = requireEntityKind(rows, phoneticScriptEntityId, "phonetic-script");
1600
+ const audioScript = findComposedAudioScript(rows, phoneticScriptEntityId, "phonetic-script");
1601
+ const segments = scriptSegments(audioScript);
1602
+ return {
1603
+ phoneticScript,
1604
+ audioScript,
1605
+ segments,
1606
+ text: segments.map((segment) => segment.text).join("")
1607
+ };
1608
+ }
1609
+ function captionSelections(caption) {
1610
+ const selections = caption.payload.selections;
1611
+ if (!Array.isArray(selections) || selections.length === 0) throw new ScriptCompositionError("empty_selection", caption.entityId, `Caption "${caption.entityId}" requires a non-empty segment selection into its AudioScript`);
1612
+ if (!selections.every(isSegmentSelection)) throw new ScriptCompositionError("invalid_selection", caption.entityId, "Caption selections require a segmentId and optional textRange");
1613
+ return selections;
1614
+ }
1615
+ function isSegmentSelection(value) {
1616
+ return typeof value === "object" && value != null && !Array.isArray(value) && typeof value.segmentId === "string" && value.segmentId.trim() !== "" && Object.keys(value).every((key) => key === "segmentId" || key === "textRange");
1617
+ }
1618
+ /** Select source text without creating another authoritative text field. */
1619
+ function selectAudioScriptSegments(script, selections) {
1620
+ if (!Array.isArray(selections) || selections.length === 0 || !selections.every(isSegmentSelection) || new Set(selections.map((s) => s.segmentId)).size !== selections.length) throw new ScriptCompositionError("invalid_selection", script.entityId, "Caption selections must be non-empty and name unique source segments");
1621
+ const bySegmentId = new Map(scriptSegments(script).map((segment) => [segment.segmentId, segment]));
1622
+ const selected = selections.map((selection) => {
1623
+ const segment = bySegmentId.get(selection.segmentId);
1624
+ if (segment === void 0) throw new ScriptCompositionError("unknown_segment", script.entityId, `Caption selection "${selection.segmentId}" does not name a segment of AudioScript "${script.entityId}"`);
1625
+ if (selection.textRange === void 0) return segment;
1626
+ const range = selection.textRange;
1627
+ const points = Array.from(segment.text);
1628
+ if (typeof range !== "object" || range === null || !Number.isSafeInteger(range.start) || !Number.isSafeInteger(range.end) || range.start < 0 || range.end <= range.start || range.end > points.length || Object.keys(range).some((key) => key !== "start" && key !== "end")) throw new ScriptCompositionError("invalid_selection", script.entityId, "Caption textRange must be a non-empty half-open Unicode code-point range within its source segment");
1629
+ return {
1630
+ ...segment,
1631
+ text: points.slice(range.start, range.end).join("")
1632
+ };
1633
+ });
1634
+ if (!selected.map((segment) => segment.text).join("").trim()) throw new ScriptCompositionError("empty_selection", script.entityId, "Caption selection must contain visible source text");
1635
+ return selected;
1636
+ }
1637
+ function requireEntityKind(rows, entityIdValue, entityKind) {
1638
+ const entity = rows.entities.find((candidate) => candidate.entityId === entityIdValue);
1639
+ if (entity === void 0) throw new ScriptCompositionError("composition_dangling", entityIdValue, `Entity "${entityIdValue}" does not exist`);
1640
+ if (entity.entityKind !== entityKind) throw new ScriptCompositionError("composition_dangling", entityIdValue, `Entity "${entityIdValue}" must have kind "${entityKind}", got "${entity.entityKind}"`);
1641
+ return entity;
1642
+ }
1643
+ //#endregion
1527
1644
  //#region ../medeo-dsl/src/ids.ts
1528
1645
  function createEntityId(value) {
1529
1646
  return createId(value, "EntityId");
@@ -1539,8 +1656,9 @@ function createId(value, label) {
1539
1656
  //#region ../medeo-dsl/src/invariants.ts
1540
1657
  /**
1541
1658
  * Media variants own their Asset identity directly: a `physical-asset`
1542
- * Relation may not bind them. Caption inline text (and other non-media
1543
- * Sequence entities) keep their Asset binding.
1659
+ * Relation may not bind them. Caption text is composed domain content, so
1660
+ * Captions do not bind Physical Assets either; the Relation vocabulary stays
1661
+ * open for future physical pipeline semantics.
1544
1662
  */
1545
1663
  function validateMediaAssetIdentity(entity, index) {
1546
1664
  return [...index.relationsOf(entity)].filter((relation) => relation.kind === "physical-asset").map(() => ({
@@ -1573,7 +1691,8 @@ function validateEntityRelationSet(entityRefs, index, options) {
1573
1691
  issues.push(...validateClipPlacement(entity, index));
1574
1692
  }
1575
1693
  if (current.entityKind === "axvideo") issues.push(...validateAXVideoAdmission(entity, index));
1576
- if (current.entityKind === "caption") issues.push(...validateCaptionAsset(entity, index));
1694
+ if (current.entityKind === "caption") issues.push(...validateCaptionComposition(entity, index));
1695
+ if (current.entityKind === "phonetic-script") issues.push(...validatePhoneticComposition(entity, index));
1577
1696
  issues.push(...validateSequenceComposition(entity));
1578
1697
  }
1579
1698
  issues.push(...validateClipAnchorCycles(entities, index));
@@ -1676,25 +1795,63 @@ function validateAXVideoAdmission(axVideo, index) {
1676
1795
  message: "AXVideo must have exactly one live AXVideo-Marker Relation"
1677
1796
  }];
1678
1797
  }
1679
- function validateCaptionAsset(caption, index) {
1680
- const assets = ofKind([...index.relationsOf(caption)], "physical-asset").map((relation) => relation.other(caption)?.deref()?.current()).filter((entity) => entity?.entityKind === "asset");
1681
- if (assets.length > 0) {
1682
- const captionText = caption.current().text;
1683
- if (!assets.some((asset) => {
1684
- const inline = asset.inline;
1685
- return isRecord(inline) && inline.mediaType === "text/plain" && inline.text !== captionText;
1686
- })) return [];
1687
- return [{
1688
- code: "caption_inline_asset_mismatch",
1689
- entityId: caption.entityId,
1690
- message: "Caption text must match the text/plain inline Physical Asset"
1691
- }];
1798
+ /**
1799
+ * Variant composition is the content contract, not an optional label: a
1800
+ * Caption must compose exactly one live AudioScript and its segment selection
1801
+ * must name that script's own segments. Text is never stored on the variant,
1802
+ * so a missing source means no valid caption content and fails validation.
1803
+ */
1804
+ function validateCaptionComposition(caption, index) {
1805
+ return validateVariantComposition(caption, index, "caption", "caption-composition", "caption_composition_required");
1806
+ }
1807
+ /** Same required-composition contract for the pronunciation variant. */
1808
+ function validatePhoneticComposition(phonetic, index) {
1809
+ return validateVariantComposition(phonetic, index, "phonetic-script", "phonetic-script-composition", "phonetic_script_composition_required");
1810
+ }
1811
+ function validateVariantComposition(variant, index, variantKind, compositionKind, issueCode) {
1812
+ const relations = [...index.relationsOf(variant)];
1813
+ const issues = [];
1814
+ const physicalEdges = ofKind(relations, "physical-asset");
1815
+ if (variantKind === "caption" && physicalEdges.length > 0) issues.push({
1816
+ code: "caption_physical_asset_forbidden",
1817
+ entityId: variant.entityId,
1818
+ message: "Caption text is composed from its AudioScript; Caption must not bind a Physical Asset"
1819
+ });
1820
+ const compositionEdges = ofKind(relations, compositionKind);
1821
+ if (compositionEdges.length !== 1) {
1822
+ issues.push({
1823
+ code: issueCode,
1824
+ entityId: variant.entityId,
1825
+ message: `${variantKind} must have exactly one ${compositionKind} Relation to a live AudioScript`
1826
+ });
1827
+ return issues;
1692
1828
  }
1693
- return [{
1694
- code: "caption_asset_required",
1695
- entityId: caption.entityId,
1696
- message: "Caption must have a Physical Asset Relation"
1697
- }];
1829
+ const script = compositionEdges[0]?.other(variant)?.deref()?.current();
1830
+ if (script?.entityKind !== "audio-script") {
1831
+ issues.push({
1832
+ code: issueCode,
1833
+ entityId: variant.entityId,
1834
+ message: `${variantKind} ${compositionKind} Relation must resolve a live AudioScript`
1835
+ });
1836
+ return issues;
1837
+ }
1838
+ if (variantKind !== "caption") return issues;
1839
+ const selections = variant.current().selections;
1840
+ if (!Array.isArray(selections)) return issues;
1841
+ try {
1842
+ selectAudioScriptSegments({
1843
+ entityId: script.entityId,
1844
+ entityKind: "audio-script",
1845
+ payload: { segments: script.segments.map((segment) => ({ ...segment })) }
1846
+ }, selections);
1847
+ } catch (error) {
1848
+ issues.push({
1849
+ code: "caption_selection_invalid",
1850
+ entityId: variant.entityId,
1851
+ message: error instanceof Error ? error.message : "Invalid Caption selection"
1852
+ });
1853
+ }
1854
+ return issues;
1698
1855
  }
1699
1856
  function validateClipPlacement(clip, index) {
1700
1857
  const marker = ofKind([...index.relationsOf(clip)], "clip-marker")[0]?.other(clip)?.deref();
@@ -1822,6 +1979,18 @@ function validateKnownEntityPayload(entity) {
1822
1979
  const value = entity;
1823
1980
  const problems = [];
1824
1981
  if (value.lifecycle !== void 0 && !isRecord(value.lifecycle)) problems.push("lifecycle must be an object when present");
1982
+ if (entity.entityKind === "audio-script" || entity.entityKind === "phonetic-script") {
1983
+ for (const key of [
1984
+ "extent",
1985
+ "sampling",
1986
+ "coordinateSpace",
1987
+ "sourceRange",
1988
+ "targetRange",
1989
+ "duration",
1990
+ "startMs",
1991
+ "endMs"
1992
+ ]) if (Object.hasOwn(value, key)) problems.push(`${key} is not intrinsic script data; assign an external annotation Marker`);
1993
+ }
1825
1994
  switch (entity.entityKind) {
1826
1995
  case "track":
1827
1996
  validateOptionalField(value, "hidden", "boolean", problems);
@@ -1848,9 +2017,11 @@ function validateKnownEntityPayload(entity) {
1848
2017
  validateMarkerPayload(value, problems);
1849
2018
  break;
1850
2019
  case "audio-script":
1851
- case "phonetic-script":
1852
2020
  validateScriptPayload(value, problems);
1853
2021
  break;
2022
+ case "phonetic-script":
2023
+ validatePhoneticScriptPayload(value, problems);
2024
+ break;
1854
2025
  case "timeline":
1855
2026
  case "viewport": break;
1856
2027
  case "clip":
@@ -1914,24 +2085,18 @@ function validateSegmentRanges(value, problems) {
1914
2085
  function validateAssetPayload(value, problems) {
1915
2086
  validateExternalLocator(value, problems);
1916
2087
  validateStorageKey(value, problems);
1917
- const inline = value.inline;
1918
- if (inline !== void 0) if (!isRecord(inline)) problems.push("inline must be an object when present");
1919
- else {
1920
- if (inline.mediaType !== "text/plain") problems.push("inline.mediaType must be \"text/plain\"");
1921
- if (typeof inline.text !== "string") problems.push("inline.text must be a string");
1922
- }
1923
- if (value.external !== void 0 && value.inline !== void 0) problems.push("Asset must not combine external and inline physical locations");
2088
+ if (value.inline !== void 0) problems.push("inline is not a physical location; text is domain content owned by its AudioScript");
1924
2089
  }
1925
2090
  /**
1926
2091
  * Media variants own their Asset locator directly: `external` is required and
1927
- * inline text stays an Asset-kind-only value so the two physical-location
2092
+ * textual domain content is owned by AudioScript; the physical-location
1928
2093
  * vocabularies cannot mix.
1929
2094
  */
1930
2095
  function validateMediaAssetFields(value, problems) {
1931
2096
  if (value.external === void 0) problems.push("external is required; media variants own their Asset identity");
1932
2097
  else validateExternalLocator(value, problems);
1933
2098
  validateStorageKey(value, problems);
1934
- if (value.inline !== void 0) problems.push("inline is an Asset-kind field; media variants use external");
2099
+ if (value.inline !== void 0) problems.push("media variants use external locators, not inline domain text");
1935
2100
  }
1936
2101
  function validateExternalLocator(value, problems) {
1937
2102
  const external = value.external;
@@ -1958,7 +2123,27 @@ function validateVoicePayload(value, problems) {
1958
2123
  if (voice.name !== void 0 && typeof voice.name !== "string") problems.push("voice.name must be a string when present");
1959
2124
  }
1960
2125
  function validateCaptionPayload(value, problems) {
1961
- if (value.text !== void 0 && typeof value.text !== "string") problems.push("text must be a string when present");
2126
+ if (value.text !== void 0) problems.push("text is composed from the AudioScript; Caption must not store a text copy");
2127
+ const selections = value.selections;
2128
+ if (!Array.isArray(selections)) problems.push("selections must be a non-empty array of AudioScript segment selections");
2129
+ else {
2130
+ if (selections.length === 0) problems.push("selections must name at least one AudioScript segment");
2131
+ const seen = /* @__PURE__ */ new Set();
2132
+ for (const [index, selection] of selections.entries()) {
2133
+ if (!isRecord(selection)) {
2134
+ problems.push(`selections[${index}] must be an object`);
2135
+ continue;
2136
+ }
2137
+ if (typeof selection.segmentId !== "string" || selection.segmentId.trim() === "") problems.push(`selections[${index}].segmentId must be a string`);
2138
+ else if (seen.has(selection.segmentId)) problems.push(`selections[${index}].segmentId must be unique within the Caption`);
2139
+ else seen.add(selection.segmentId);
2140
+ if (Object.keys(selection).some((key) => key !== "segmentId" && key !== "textRange")) problems.push(`selections[${index}] may only contain segmentId and textRange`);
2141
+ if (selection.textRange !== void 0) {
2142
+ const range = selection.textRange;
2143
+ if (!isRecord(range) || !Number.isSafeInteger(range.start) || !Number.isSafeInteger(range.end) || range.start < 0 || range.end <= range.start || Object.keys(range).some((key) => key !== "start" && key !== "end")) problems.push(`selections[${index}].textRange must be a non-empty half-open code-point range`);
2144
+ }
2145
+ }
2146
+ }
1962
2147
  const style = value.style;
1963
2148
  if (style === void 0) return;
1964
2149
  if (!isRecord(style)) {
@@ -1993,6 +2178,13 @@ function validateRange(value, path, required, problems) {
1993
2178
  if (!Object.hasOwn(value, "start") || value.start === void 0) problems.push(`${path}.start is required`);
1994
2179
  if (!Object.hasOwn(value, "end") || value.end === void 0) problems.push(`${path}.end is required`);
1995
2180
  }
2181
+ /** Phonetic variants store pronunciation fields only; base text stays in the AudioScript. */
2182
+ function validatePhoneticScriptPayload(value, problems) {
2183
+ if (value.text !== void 0) problems.push("text is composed from AudioScript; PhoneticScript must not store a text copy");
2184
+ if (value.segments !== void 0) problems.push("segments carry the base text owned by the AudioScript; PhoneticScript stores pronunciation fields only");
2185
+ if (value.phonemeScript !== void 0 && (typeof value.phonemeScript !== "string" || value.phonemeScript.trim() === "")) problems.push("phonemeScript must be a non-empty string when present");
2186
+ if (value.prosody !== void 0 && !isRecord(value.prosody)) problems.push("prosody must be an object when present");
2187
+ }
1996
2188
  function validateScriptPayload(value, problems) {
1997
2189
  if (!Array.isArray(value.segments)) {
1998
2190
  problems.push("segments must be an array");
@@ -2071,16 +2263,17 @@ function isOwnedLocalEntityValuePath(entityKind, path) {
2071
2263
  ].includes(entityKind) && /^(?:sampling|coordinateSpace|coordinateSpace\.unit|extent\.kind)$/.test(path)) return true;
2072
2264
  if (entityKind === "sequence-marker" && /^(?:durationPolicy|duration\.mode|timeRemapping\.(?:kind|mode))$/.test(path)) return true;
2073
2265
  if (entityKind === "sequence-marker" && /^segmentRanges\[\d+\]\.segmentId$/.test(path)) return true;
2074
- if (entityKind === "asset" && /^(?:external\.(?:system|key)|storageKey|inline\.(?:mediaType|text))$/.test(path)) return true;
2266
+ if (entityKind === "asset" && /^(?:external\.(?:system|key)|storageKey)$/.test(path)) return true;
2075
2267
  if (isMediaAssetVariantKind(entityKind) && /^(?:external\.(?:system|key)|storageKey)$/.test(path)) return true;
2076
2268
  if (entityKind === "voice" && /^voice\.(?:system|key|name)$/.test(path)) return true;
2077
- if (entityKind === "caption" && (path === "text" || path.startsWith("style."))) return true;
2078
- if ((entityKind === "audio-script" || entityKind === "phonetic-script") && /^segments\[\d+\]\.(?:segmentId|text|language)$/.test(path)) return true;
2269
+ if (entityKind === "caption" && (path.startsWith("style.") || /^selections\[\d+\]\.segmentId$/.test(path))) return true;
2270
+ if (entityKind === "audio-script" && /^segments\[\d+\]\.(?:segmentId|text|language)$/.test(path)) return true;
2079
2271
  return false;
2080
2272
  }
2081
2273
  function isOwnedLocalIdPath(entityKind, path) {
2082
2274
  if (path === "lifecycle.actorId") return true;
2083
- if ((entityKind === "audio-script" || entityKind === "phonetic-script") && /^segments\[\d+\]\.segmentId$/.test(path)) return true;
2275
+ if (entityKind === "audio-script" && /^segments\[\d+\]\.segmentId$/.test(path)) return true;
2276
+ if (entityKind === "caption" && /^selections\[\d+\]\.segmentId$/.test(path)) return true;
2084
2277
  if (entityKind === "sequence-marker" && /^segmentRanges\[\d+\]\.segmentId$/.test(path)) return true;
2085
2278
  if (entityKind === "asset" && /^(?:tracks\[\d+\]\.trackId|renditions\[\d+\]\.renditionId)$/.test(path)) return true;
2086
2279
  return false;
@@ -2187,8 +2380,15 @@ const generatedRelationSpec = Object.freeze({
2187
2380
  validateEndpoints: (endpoints) => endpoints.every((endpoint) => isGeneratedMedia(endpoint.current())),
2188
2381
  validateMetadata: isEmptyMetadata
2189
2382
  });
2190
- const phoneticScriptProvenanceRelationSpec = metadataSpec("phonetic-script-provenance", "phonetic-script", "audio-script", isSegmentAlignmentMetadata);
2191
- const captionProvenanceRelationSpec = metadataSpec("caption-provenance", "caption", "audio-script", isSegmentAlignmentMetadata);
2383
+ /**
2384
+ * Variant composition: the required content relation between a variant and its
2385
+ * AudioScript. This is the assembly source for the variant's base text — never
2386
+ * a downgradeable provenance label. A variant without exactly one live
2387
+ * composition Relation has no valid content and fails validation.
2388
+ */
2389
+ const phoneticScriptCompositionRelationSpec = metadataSpec("phonetic-script-composition", "phonetic-script", "audio-script", isSegmentAlignmentMetadata);
2390
+ /** See {@link phoneticScriptCompositionRelationSpec}; Caption is the display variant. */
2391
+ const captionCompositionRelationSpec = metadataSpec("caption-composition", "caption", "audio-script", isSegmentAlignmentMetadata);
2192
2392
  const captionAlignmentRelationSpec = Object.freeze({
2193
2393
  kind: "caption-alignment",
2194
2394
  validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["caption"]), new Set(["audio", "voice"])),
@@ -2200,19 +2400,20 @@ const clipAnchorRelationSpec = Object.freeze({
2200
2400
  validateEndpoints: (endpoints) => endpoints[0].current().entityKind === "clip" && endpoints[1].current().entityKind === "clip",
2201
2401
  validateMetadata: isEmptyMetadata
2202
2402
  });
2203
- /** `audio-script-render(output, script)` means endpoint 0 was rendered from endpoint 1. */
2204
- const audioScriptRenderRelationSpec = Object.freeze({
2205
- kind: "audio-script-render",
2206
- validateEndpoints: (endpoints) => {
2207
- const outputKind = endpoints[0].current().entityKind;
2208
- return (outputKind === "audio" || outputKind === "voice") && endpoints[1].current().entityKind === "audio-script";
2209
- },
2403
+ /** Voice is generated from PhoneticScript; kinds determine roles regardless of endpoint positions. */
2404
+ const phoneticScriptRenderRelationSpec = Object.freeze({
2405
+ kind: "phonetic-script-render",
2406
+ validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["voice"]), new Set(["phonetic-script"])),
2210
2407
  validateMetadata: isEmptyMetadata
2211
2408
  });
2212
- /** `audio-script-source(script, source)` means endpoint 0 was transcribed from endpoint 1. */
2409
+ /** AudioScript was transcribed from Audio, Video, or recorded Voice; kinds determine roles. */
2213
2410
  const audioScriptSourceRelationSpec = Object.freeze({
2214
2411
  kind: "audio-script-source",
2215
- validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["audio-script"]), new Set(["audio", "video"])),
2412
+ validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["audio-script"]), new Set([
2413
+ "audio",
2414
+ "video",
2415
+ "voice"
2416
+ ])),
2216
2417
  validateMetadata: isEmptyMetadata
2217
2418
  });
2218
2419
  /**
@@ -2236,11 +2437,11 @@ const builtInRelationSpecs = Object.freeze([
2236
2437
  markerTimelineRelationSpec,
2237
2438
  physicalAssetRelationSpec,
2238
2439
  generatedRelationSpec,
2239
- phoneticScriptProvenanceRelationSpec,
2240
- captionProvenanceRelationSpec,
2440
+ phoneticScriptCompositionRelationSpec,
2441
+ captionCompositionRelationSpec,
2241
2442
  captionAlignmentRelationSpec,
2242
2443
  clipAnchorRelationSpec,
2243
- audioScriptRenderRelationSpec,
2444
+ phoneticScriptRenderRelationSpec,
2244
2445
  audioScriptSourceRelationSpec,
2245
2446
  audioScriptMarkerRelationSpec
2246
2447
  ]);
@@ -2339,7 +2540,7 @@ var BiRelationIndex = class {
2339
2540
  byRelationId = /* @__PURE__ */ new Map();
2340
2541
  link(input) {
2341
2542
  if (input.spec.kind === "generated") throw new Error("Author generated Relations with linkGenerated({ output, input })");
2342
- if (input.spec.kind === "clip-anchor" || input.spec.kind === "audio-script-render" || input.spec.kind === "audio-script-source") throw new Error(`Author ordered ${input.spec.kind} Relations with the dedicated role-named method`);
2543
+ if (input.spec.kind === "clip-anchor" || input.spec.kind === "phonetic-script-render" || input.spec.kind === "audio-script-source") throw new Error(`Author ordered ${input.spec.kind} Relations with the dedicated role-named method`);
2343
2544
  return this.linkValidated(input);
2344
2545
  }
2345
2546
  /** Author `generated(output, input)` without exposing positional arguments. */
@@ -2362,12 +2563,12 @@ var BiRelationIndex = class {
2362
2563
  trace: input.trace
2363
2564
  });
2364
2565
  }
2365
- /** Author `audio-script-render(output, script)` without exposing positional arguments. */
2366
- linkAudioScriptRender(input) {
2566
+ /** Author `phonetic-script-render(output, phoneticScript)` without exposing positional arguments. */
2567
+ linkPhoneticScriptRender(input) {
2367
2568
  return this.linkValidated({
2368
2569
  relationId: input.relationId,
2369
- spec: audioScriptRenderRelationSpec,
2370
- endpoints: [input.output, input.script],
2570
+ spec: phoneticScriptRenderRelationSpec,
2571
+ endpoints: [input.output, input.phoneticScript],
2371
2572
  metadata: {},
2372
2573
  trace: input.trace
2373
2574
  });
@@ -2860,7 +3061,7 @@ function projectEntityTimeline(rows, meta) {
2860
3061
  const asset = mediaAssetFacts(graph, content);
2861
3062
  requireUntrimmedAudio(content, marker, placement);
2862
3063
  const external = externalLocator(asset, "memota-speech");
2863
- const script = graph.one(content.entityId, "audio-script-render", "audio-script");
3064
+ const assembled = graph.adjacent(content.entityId, "phonetic-script-render").length > 0 || content.payload.voice !== void 0 ? assemblePhoneticScriptContent(rows, graph.one(content.entityId, "phonetic-script-render", "phonetic-script").entityId) : void 0;
2864
3065
  const voice = content.payload.voice;
2865
3066
  if (voice !== void 0 && (!object(voice) || voice.system !== "voice-library" || typeof voice.key !== "string")) fail("Voice must use an explicit voice-library locator");
2866
3067
  const captionIds = layout.tracks.flatMap((candidate) => candidate.role === "caption" ? candidate.clips.filter((caption) => caption.anchorClipEntityId === clip.entityId).map((caption) => caption.clipEntityId) : []);
@@ -2870,7 +3071,7 @@ function projectEntityTimeline(rows, meta) {
2870
3071
  media_duration_ms: placement.duration,
2871
3072
  audio_storage_key: storageKey(asset),
2872
3073
  origin_speech_id: external.key,
2873
- audio_script: scriptText(script),
3074
+ audio_script: assembled?.text ?? (graph.adjacent(content.entityId, "audio-script-source").length > 0 ? assembleScriptText(graph.one(content.entityId, "audio-script-source", "audio-script")) : ""),
2874
3075
  volume: volume.data,
2875
3076
  voice: object(voice) ? {
2876
3077
  id: typeof voice.key === "string" ? voice.key : void 0,
@@ -2879,12 +3080,7 @@ function projectEntityTimeline(rows, meta) {
2879
3080
  caption_ids: captionIds
2880
3081
  } };
2881
3082
  } else if (track.role === "caption") {
2882
- const text = content.payload.text;
2883
- if (typeof text !== "string") fail("Caption " + content.entityId + " requires its text");
2884
- const asset = graph.one(content.entityId, "physical-asset", "asset");
2885
- const inline = asset.payload.inline;
2886
- if (inline !== void 0 && (!object(inline) || inline.mediaType !== "text/plain" || inline.text !== text)) fail("Inline Caption Asset and Caption text must agree");
2887
- if (inline === void 0 && !object(asset.payload.external)) fail("Caption Asset must identify physical text or contain actual inline text");
3083
+ const text = assembleCaptionContent(rows, content.entityId).text;
2888
3084
  if (marker.payload.timeRemapping !== void 0) fail("Caption timeRemapping is not supported by this reader");
2889
3085
  const style = captionStyle(content.payload.style);
2890
3086
  const anchor = placement.anchorClipEntityId === void 0 ? void 0 : layout.clips.get(placement.anchorClipEntityId);
@@ -2972,14 +3168,6 @@ function storageKey(asset) {
2972
3168
  if (typeof asset.payload.storageKey !== "string" || asset.payload.storageKey.trim() === "") fail("Asset " + asset.entityId + " requires its factual storageKey");
2973
3169
  return asset.payload.storageKey;
2974
3170
  }
2975
- function scriptText(script) {
2976
- const segments = script.payload.segments;
2977
- if (!Array.isArray(segments)) fail("AudioScript requires segments");
2978
- return segments.map((segment) => {
2979
- if (!object(segment) || typeof segment.text !== "string") fail("AudioScript segment requires text");
2980
- return segment.text;
2981
- }).join("");
2982
- }
2983
3171
  function captionStyle(value) {
2984
3172
  if (value === void 0) return void 0;
2985
3173
  if (!object(value)) fail("Caption style must be an object");
@@ -3351,4 +3539,4 @@ function createPlainMemoryAdapter(document, options) {
3351
3539
  return new PlainMemoryAdapter(document, options);
3352
3540
  }
3353
3541
  //#endregion
3354
- export { videoDocumentMirrorSchema as $, ensureLaneTrack as A, resolveSpeechOverlapByShiftingVideos as B, toVideoDocument as C, partUnionSchema as D, validateVideoDocument as E, arrangeMainTrackSeamlessly as F, safeDurationMs as G, TIMELINE_SKELETON_DURATION_MS as H, fillMainTrackTimeGaps as I, VIDEO_DOCUMENT_SCHEMA_VERSION as J, DEFAULT_UNIT_TIME_MS as K, reassignSpeechesToVideoClipsByTime as L, laneTrackId as M, solveVideoDocument as N, videoDocumentSchema as O, cascadeAfterVideoClipChanges as P, recordEntries as Q, recalculateTimelineDuration as R, fromVideoDocument as S, assertValidVideoDocument as T, isEmptyVideoClip as U, syncAggregatedClipsTimePosition as V, partDurationMs as W, speedOf as X, effectiveVideoClipDurationMs as Y, partUnionToDraft as Z, hasSequence as _, applyEntityTimelineProjection as a, buildSpeechHostMap as b, writeVideoDocumentToDraft as c, resolveEntityTimelineLayout as d, base64ToBytes as et, EntityTimelineProjectionError as f, createRelationId as g, createEntityId as h, MirrorVideoDocumentAdapter as i, findLaneTrack as j, LANE_KINDS_IN_STACK_ORDER as k, readVideoDocumentFromDraft as l, isJsonObject as m, createPlainMemoryAdapter as n, createMirrorVideoDocument as o, decodeEntityRelationRows as p, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION as q, generatePartId as r, createMirrorVideoDocumentAdapter as s, PlainMemoryAdapter as t, bytesToBase64 as tt, projectEntityTimeline as u, isMediaAssetVariantKind as v, VideoDocumentValidationError as w, derivePositionFromAbs as x, buildInitialVideoDocument as y, resolveAllSpeechOverlaps as z };
3542
+ export { ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION as $, VideoDocumentValidationError as A, cascadeAfterVideoClipChanges as B, hasSequence as C, derivePositionFromAbs as D, buildSpeechHostMap as E, LANE_KINDS_IN_STACK_ORDER as F, resolveAllSpeechOverlaps as G, fillMainTrackTimeGaps as H, ensureLaneTrack as I, TIMELINE_SKELETON_DURATION_MS as J, resolveSpeechOverlapByShiftingVideos as K, findLaneTrack as L, validateVideoDocument as M, partUnionSchema as N, fromVideoDocument as O, videoDocumentSchema as P, DEFAULT_UNIT_TIME_MS as Q, laneTrackId as R, selectAudioScriptSegments as S, buildInitialVideoDocument as T, reassignSpeechesToVideoClipsByTime as U, arrangeMainTrackSeamlessly as V, recalculateTimelineDuration as W, partDurationMs as X, isEmptyVideoClip as Y, safeDurationMs as Z, ScriptCompositionError as _, applyEntityTimelineProjection as a, videoDocumentMirrorSchema as at, assembleScriptText as b, writeVideoDocumentToDraft as c, resolveEntityTimelineLayout as d, VIDEO_DOCUMENT_SCHEMA_VERSION as et, EntityTimelineProjectionError as f, createRelationId as g, createEntityId as h, MirrorVideoDocumentAdapter as i, recordEntries as it, assertValidVideoDocument as j, toVideoDocument as k, readVideoDocumentFromDraft as l, isJsonObject as m, createPlainMemoryAdapter as n, speedOf as nt, createMirrorVideoDocument as o, base64ToBytes as ot, decodeEntityRelationRows as p, syncAggregatedClipsTimePosition as q, generatePartId as r, partUnionToDraft as rt, createMirrorVideoDocumentAdapter as s, bytesToBase64 as st, PlainMemoryAdapter as t, effectiveVideoClipDurationMs as tt, projectEntityTimeline as u, assembleCaptionContent as v, isMediaAssetVariantKind as w, findComposedAudioScript as x, assemblePhoneticScriptContent as y, solveVideoDocument as z };
@@ -849,6 +849,13 @@ type RelationId = string & {
849
849
  readonly [relationIdBrand]: 'RelationId';
850
850
  };
851
851
  //#endregion
852
+ //#region ../medeo-dsl/src/json-values.d.ts
853
+ type JsonPrimitive = string | number | boolean | null;
854
+ type JsonValue = JsonPrimitive | JsonObject | readonly JsonValue[];
855
+ type JsonObject = {
856
+ readonly [key: string]: JsonValue;
857
+ };
858
+ //#endregion
852
859
  //#region ../medeo-dsl/src/entities.d.ts
853
860
  type KnownEntityKind = 'axvideo' | 'timeline' | 'track' | 'clip' | 'asset' | 'video' | 'audio' | 'voice' | 'image' | 'sequence-marker' | 'viewport' | 'audio-script' | 'phonetic-script' | 'caption';
854
861
  declare const extensionEntityKindBrand: unique symbol;
@@ -867,6 +874,11 @@ type SequenceDuration<Span = unknown> = {
867
874
  readonly mode: 'fixed';
868
875
  readonly value: Span;
869
876
  };
877
+ interface ScriptTextSegment {
878
+ readonly segmentId: string;
879
+ readonly text: string;
880
+ readonly language?: string;
881
+ }
870
882
  interface VoiceDescriptor {
871
883
  readonly system: 'voice-library';
872
884
  readonly key: string;
@@ -888,16 +900,31 @@ interface CaptionStyleFields {
888
900
  readonly positionX?: number;
889
901
  readonly positionY?: number;
890
902
  }
891
- //#endregion
892
- //#region ../medeo-dsl/src/json-values.d.ts
893
- type JsonPrimitive = string | number | boolean | null;
894
- type JsonValue = JsonPrimitive | JsonObject | readonly JsonValue[];
895
- type JsonObject = {
896
- readonly [key: string]: JsonValue;
903
+ /**
904
+ * Half-open `[start, end)` position window inside one Segment's text, counted
905
+ * in Unicode code points (not UTF-16 code units), so a boundary never splits a
906
+ * surrogate pair. Positions are non-negative safe integers with `start < end`;
907
+ * `end` must not exceed the Segment's code-point length.
908
+ */
909
+ interface CaptionTextRange extends JsonObject {
910
+ readonly start: number;
911
+ readonly end: number;
912
+ }
913
+ /**
914
+ * One ordered entry of the Caption's segment selection. `segmentId` quotes the
915
+ * composed AudioScript's own stable segment identity — a local id quoted by the
916
+ * variant, never a peer Entity reference. Text itself is never copied here;
917
+ * complete Caption content is assembled along the caption-composition Relation.
918
+ * The optional `textRange` narrows one Segment to an intra-Segment sub-span
919
+ * (intra-segment re-segmentation); without it the whole Segment text is selected.
920
+ */
921
+ type CaptionSegmentSelection = JsonObject & {
922
+ readonly segmentId: string;
923
+ readonly textRange?: CaptionTextRange;
897
924
  };
898
925
  //#endregion
899
926
  //#region ../medeo-dsl/src/relations.d.ts
900
- type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'physical-asset' | 'generated' | 'phonetic-script-provenance' | 'caption-provenance' | 'caption-alignment' | 'clip-anchor' | 'audio-script-render' | 'audio-script-source' | 'audio-script-marker';
927
+ type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'physical-asset' | 'generated' | 'phonetic-script-composition' | 'caption-composition' | 'caption-alignment' | 'clip-anchor' | 'phonetic-script-render' | 'audio-script-source' | 'audio-script-marker';
901
928
  type RelationKind = KnownRelationKind | (string & {});
902
929
  type RelationTrace = JsonObject;
903
930
  /**
@@ -1655,10 +1682,10 @@ declare const videoDocumentSchema: z.ZodObject<{
1655
1682
  tracks: z.ZodOptional<z.ZodArray<z.ZodObject<{
1656
1683
  id: z.ZodOptional<z.ZodString>;
1657
1684
  parts_kind: z.ZodOptional<z.ZodEnum<{
1685
+ video_clip: "video_clip";
1658
1686
  speech: "speech";
1659
1687
  caption: "caption";
1660
1688
  bgm: "bgm";
1661
- video_clip: "video_clip";
1662
1689
  }>>;
1663
1690
  is_hidden: z.ZodOptional<z.ZodBoolean>;
1664
1691
  items: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -1740,4 +1767,4 @@ declare const videoDocumentSchema: z.ZodObject<{
1740
1767
  }, z.core.$loose>]>>>;
1741
1768
  }, z.core.$loose>;
1742
1769
  //#endregion
1743
- export { VoiceDescriptor as $, generatePartId as A, Attachment as At, ResolvedEntityClipPlacement as B, PlannedSemanticOpKind as C, VideoDocumentSchemaVersion as Ct, SnapshotReadable as D, VideoDraftPartUnion as Dt, SchemaValidator as E, VideoDraft as Et, videoDocumentMirrorSchema as F, Timeline$1 as Ft, EntityTimelineProjectionError as G, ResolvedEntityTrack as H, VideoDocumentValidationError as I, Track$1 as It, JsonObject as J, EntityRelationRows as K, assertValidVideoDocument as L, TrackItem$1 as Lt, TrackItemDraft as M, CaptionStyle as Mt, VideoDocumentDraft as N, PartAggregation as Nt, ValidationError as O, effectiveVideoClipDurationMs as Ot, VideoDocumentMirrorSchema as P, SpeedShift as Pt, SequenceRange as Q, validateVideoDocument as R, ImplementedSemanticOpKind as S, VideoDocument as St, isImplementedSemanticOpKind as T, VideoDocumentValidationIssueCode as Tt, resolveEntityTimelineLayout as U, ResolvedEntityTimelineLayout as V, projectEntityTimeline as W, CaptionStyleFields as X, JsonValue as Y, SequenceDuration as Z, SemanticEditor as _, Track as _t, PlainMemoryAdapter as a, buildSpeechHostMap as at, TransactAudit as b, VIDEO_DOCUMENT_SCHEMA_VERSION as bt, MirrorVideoDocumentAdapter as c, toVideoDocument as ct, createMirrorVideoDocument as d, DEFAULT_UNIT_TIME_MS as dt, EntityId as et, createMirrorVideoDocumentAdapter as f, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION as ft, SemanticDocumentAdapter as g, Timeline as gt, OpActor as h, SpeechPart as ht, JournalEntry as i, SpeechHostMap as it, TrackDraft as j, CaptionPart$1 as jt, PartIdFactory as k, speedOf as kt, MirrorVideoDocumentOptions as l, BgmPart as lt, CommitOptions as m, PartUnion as mt, videoDocumentSchema as n, buildInitialVideoDocument as nt, PlainMemoryAdapterOptions as o, derivePositionFromAbs as ot, writeVideoDocumentToDraft as p, PartKind as pt, EntityRow as q, readVideoDocumentFromDraft as r, DerivedItemPosition as rt, createPlainMemoryAdapter as s, fromVideoDocument as st, partUnionSchema as t, InitialDocumentFacts as tt, applyEntityTimelineProjection as u, CaptionPart as ut, SemanticOpInput as v, TrackItem as vt, SemanticOpKind as w, VideoDocumentValidationIssue as wt, IMPLEMENTED_SEMANTIC_OP_KINDS as x, VideoClipPart as xt, SemanticOpName as y, TrackItemTimePosition as yt, EntityTimelineTrackRole as z };
1770
+ export { VoiceDescriptor as $, generatePartId as A, effectiveVideoClipDurationMs as At, ResolvedEntityClipPlacement as B, PlannedSemanticOpKind as C, VideoClipPart as Ct, SnapshotReadable as D, VideoDocumentValidationIssueCode as Dt, SchemaValidator as E, VideoDocumentValidationIssue as Et, videoDocumentMirrorSchema as F, PartAggregation as Ft, EntityTimelineProjectionError as G, ResolvedEntityTrack as H, VideoDocumentValidationError as I, SpeedShift as It, CaptionSegmentSelection as J, EntityRelationRows as K, assertValidVideoDocument as L, Timeline$1 as Lt, TrackItemDraft as M, Attachment as Mt, VideoDocumentDraft as N, CaptionPart$1 as Nt, ValidationError as O, VideoDraft as Ot, VideoDocumentMirrorSchema as P, CaptionStyle as Pt, SequenceRange as Q, validateVideoDocument as R, Track$1 as Rt, ImplementedSemanticOpKind as S, VIDEO_DOCUMENT_SCHEMA_VERSION as St, isImplementedSemanticOpKind as T, VideoDocumentSchemaVersion as Tt, resolveEntityTimelineLayout as U, ResolvedEntityTimelineLayout as V, projectEntityTimeline as W, ScriptTextSegment as X, CaptionStyleFields as Y, SequenceDuration as Z, SemanticEditor as _, SpeechPart as _t, PlainMemoryAdapter as a, DerivedItemPosition as at, TransactAudit as b, TrackItem as bt, MirrorVideoDocumentAdapter as c, derivePositionFromAbs as ct, createMirrorVideoDocument as d, BgmPart as dt, JsonObject as et, createMirrorVideoDocumentAdapter as f, CaptionPart as ft, SemanticDocumentAdapter as g, PartUnion as gt, OpActor as h, PartKind as ht, JournalEntry as i, buildInitialVideoDocument as it, TrackDraft as j, speedOf as jt, PartIdFactory as k, VideoDraftPartUnion as kt, MirrorVideoDocumentOptions as l, fromVideoDocument as lt, CommitOptions as m, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION as mt, videoDocumentSchema as n, EntityId as nt, PlainMemoryAdapterOptions as o, SpeechHostMap as ot, writeVideoDocumentToDraft as p, DEFAULT_UNIT_TIME_MS as pt, EntityRow as q, readVideoDocumentFromDraft as r, InitialDocumentFacts as rt, createPlainMemoryAdapter as s, buildSpeechHostMap as st, partUnionSchema as t, JsonValue as tt, applyEntityTimelineProjection as u, toVideoDocument as ut, SemanticOpInput as v, Timeline as vt, SemanticOpKind as w, VideoDocument as wt, IMPLEMENTED_SEMANTIC_OP_KINDS as x, TrackItemTimePosition as xt, SemanticOpName as y, Track as yt, EntityTimelineTrackRole as z, TrackItem$1 as zt };