@mengine/medeo-client 1.3.1-alpha.1 → 1.3.1-alpha.2
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 +11 -6
- package/dist/{document-Bf200CmD.js → document-BLYcbv8E.js} +221 -140
- package/dist/{index-PYtGeXNk.d.ts → index-Dxxu0Mi1.d.ts} +2 -2
- package/dist/index.d.ts +27 -25
- package/dist/index.js +120 -46
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -74,18 +74,17 @@ plan. A speech-overlap shift is explicit placement on the real visual Clips;
|
|
|
74
74
|
an uncovered time interval does not require an invented empty-media entity.
|
|
75
75
|
|
|
76
76
|
Generated Voice links to a pre-existing PhoneticScript through `phonetic-script-render`.
|
|
77
|
-
Caption and PhoneticScript each compose a real AudioScript
|
|
78
|
-
`
|
|
79
|
-
`segments[].text`; the variants never persist a text copy. Read complete content
|
|
77
|
+
Caption and PhoneticScript each compose a real AudioScript by directly holding `baseEntityIds`, an array that may compose multiple entities. AudioScript owns
|
|
78
|
+
`segments[].text`; assembly never automatically persists a copy on the variants. Read complete content
|
|
80
79
|
with `assembleCaptionContent` or `assemblePhoneticScriptContent`. Broken composition
|
|
81
|
-
fails explicitly. Recorded Audio/Video/Voice can be the ASR source via
|
|
80
|
+
fails explicitly. Same-name fields from different bases are rejected even for equal values and even if the variant declares that field. After base fields are unambiguous, explicit own fields may override them without mutating the bases. Recorded Audio/Video/Voice can be the ASR source via
|
|
82
81
|
`audio-script-source`, without creating a synthesis variant.
|
|
83
82
|
|
|
84
|
-
`insertCaptionClip` requires `
|
|
83
|
+
`insertCaptionClip` requires `baseEntityIds` and `selections`. Each selection
|
|
85
84
|
names a source `segmentId` and optionally a half-open Unicode code-point
|
|
86
85
|
`textRange: {start, end}`. This permits display re-segmentation without rewriting
|
|
87
86
|
the original script. `upsertVoiceoverTake` requires the real
|
|
88
|
-
`phoneticScriptEntityId` used for synthesis; its captions select the same script.
|
|
87
|
+
`phoneticScriptEntityId` used for synthesis; its captions supply their own `baseEntityIds` and select the same script.
|
|
89
88
|
External speech identity and storage key stay on Voice.
|
|
90
89
|
|
|
91
90
|
AudioScript has no intrinsic Sequence and cannot enter a Clip. `audio-script-marker`
|
|
@@ -107,3 +106,9 @@ It rejects `video-document/entity-projection-v1` documents. Production entity
|
|
|
107
106
|
tools and editor adapters must not fall back to it or raw `/updates` on failure.
|
|
108
107
|
For an entity projection, `meta.version` is the committed entity revision; the
|
|
109
108
|
Loro version vector remains the transport-sync cursor.
|
|
109
|
+
|
|
110
|
+
### Transparent variant fields in the DSL sandbox
|
|
111
|
+
|
|
112
|
+
`entities.get/list` return complete assembled fields. Consumers do not query base IDs or merge source payloads. `entities.update` patches supplied fields, preserves omitted fields, and routes inherited fields to their declaring entity. Explicit own-field declarations use `entities.declareFields`; these override unambiguous base fields without changing the base. Persisted entity rows and command payloads contain owned fields only. Base collisions are validated before own overrides.
|
|
113
|
+
|
|
114
|
+
`prepareCaptionContent` accepts caption authoring intent and handles source composition, visible text selection, and preservation of existing intrinsic timing inside the SDK.
|
|
@@ -1524,13 +1524,49 @@ 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/ids.ts
|
|
1528
|
+
function createEntityId(value) {
|
|
1529
|
+
return createId(value, "EntityId");
|
|
1530
|
+
}
|
|
1531
|
+
function createRelationId(value) {
|
|
1532
|
+
return createId(value, "RelationId");
|
|
1533
|
+
}
|
|
1534
|
+
function createId(value, label) {
|
|
1535
|
+
if (value.length === 0 || value.trim() !== value) throw new Error(`${label} must be a non-empty trimmed string`);
|
|
1536
|
+
return value;
|
|
1537
|
+
}
|
|
1538
|
+
//#endregion
|
|
1539
|
+
//#region ../medeo-dsl/src/json-values.ts
|
|
1540
|
+
const nativeObjectConstructorSource = Function.prototype.toString.call(Object);
|
|
1541
|
+
function isJsonObject(value) {
|
|
1542
|
+
return isJsonValue(value, /* @__PURE__ */ new Set()) && !Array.isArray(value) && value !== null;
|
|
1543
|
+
}
|
|
1544
|
+
function isJsonValue(value, ancestors) {
|
|
1545
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
1546
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
1547
|
+
if (typeof value !== "object") return false;
|
|
1548
|
+
if (!Array.isArray(value) && !isPlainObject(value)) return false;
|
|
1549
|
+
if (ancestors.has(value)) return false;
|
|
1550
|
+
ancestors.add(value);
|
|
1551
|
+
const valid = Array.isArray(value) ? value.every((item) => isJsonValue(item, ancestors)) : Object.values(value).every((item) => isJsonValue(item, ancestors));
|
|
1552
|
+
ancestors.delete(value);
|
|
1553
|
+
return valid;
|
|
1554
|
+
}
|
|
1555
|
+
/** Recognize an ordinary object from any VM realm without admitting class instances. */
|
|
1556
|
+
function isPlainObject(value) {
|
|
1557
|
+
try {
|
|
1558
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1559
|
+
if (prototype === null) return true;
|
|
1560
|
+
if (Object.getPrototypeOf(prototype) !== null) return false;
|
|
1561
|
+
const constructor = Object.getOwnPropertyDescriptor(prototype, "constructor")?.value;
|
|
1562
|
+
return typeof constructor === "function" && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === nativeObjectConstructorSource;
|
|
1563
|
+
} catch {
|
|
1564
|
+
return false;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
//#endregion
|
|
1527
1568
|
//#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
|
-
*/
|
|
1569
|
+
/** Assembly fails explicitly when declared bases cannot provide valid, unambiguous content. */
|
|
1534
1570
|
var ScriptCompositionError = class extends Error {
|
|
1535
1571
|
code;
|
|
1536
1572
|
entityId;
|
|
@@ -1541,23 +1577,111 @@ var ScriptCompositionError = class extends Error {
|
|
|
1541
1577
|
this.name = "ScriptCompositionError";
|
|
1542
1578
|
}
|
|
1543
1579
|
};
|
|
1544
|
-
|
|
1545
|
-
|
|
1580
|
+
/** Direct base IDs are structural fields, never ordinary Relation endpoints. */
|
|
1581
|
+
function variantBaseEntityIds(entity) {
|
|
1582
|
+
if (!Object.hasOwn(entity.payload, "baseEntityIds")) return [];
|
|
1583
|
+
const ids = entity.payload.baseEntityIds;
|
|
1584
|
+
if (!Array.isArray(ids) || ids.length === 0 || !ids.every((id) => typeof id === "string" && id.trim() === id && id.length > 0) || new Set(ids).size !== ids.length) throw new ScriptCompositionError("invalid_bases", entity.entityId, `Entity "${entity.entityId}" requires non-empty, unique baseEntityIds`);
|
|
1585
|
+
return ids.map(createEntityId);
|
|
1586
|
+
}
|
|
1587
|
+
/** Validate all base providers before applying explicit own fields; ordering cannot resolve ambiguity. */
|
|
1588
|
+
function assembleEntityContent(rows, entityId) {
|
|
1589
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1590
|
+
for (const row of rows.entities) {
|
|
1591
|
+
if (byId.has(row.entityId)) throw new ScriptCompositionError("composition_ambiguous", row.entityId, `duplicate entity id "${row.entityId}"`);
|
|
1592
|
+
byId.set(row.entityId, row);
|
|
1593
|
+
}
|
|
1594
|
+
const active = /* @__PURE__ */ new Set();
|
|
1595
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1596
|
+
const visit = (id) => {
|
|
1597
|
+
const cached = cache.get(id);
|
|
1598
|
+
if (cached !== void 0) return cached;
|
|
1599
|
+
if (active.has(id)) throw new ScriptCompositionError("composition_cycle", id, `Cyclic baseEntityIds at "${id}"`);
|
|
1600
|
+
const row = byId.get(id);
|
|
1601
|
+
if (row === void 0) throw new ScriptCompositionError("composition_dangling", id, `Missing base entity "${id}" in this document`);
|
|
1602
|
+
if (!isJsonObject(row.payload) || Object.hasOwn(row.payload, "entityId") || Object.hasOwn(row.payload, "entityKind")) throw new ScriptCompositionError("invalid_bases", id, `Entity "${id}" requires JSON own fields without reserved identity fields`);
|
|
1603
|
+
active.add(id);
|
|
1604
|
+
const inherited = {};
|
|
1605
|
+
const providers = /* @__PURE__ */ new Map();
|
|
1606
|
+
for (const baseId of variantBaseEntityIds(row)) {
|
|
1607
|
+
const base = visit(baseId);
|
|
1608
|
+
for (const [field, value] of Object.entries(base.payload)) {
|
|
1609
|
+
if (field === "baseEntityIds") continue;
|
|
1610
|
+
const previous = providers.get(field);
|
|
1611
|
+
if (previous !== void 0) throw new ScriptCompositionError("field_conflict", id, `Entity "${id}" field "${field}" conflicts between bases "${previous}" and "${baseId}"; own fields cannot resolve base ambiguity`);
|
|
1612
|
+
providers.set(field, baseId);
|
|
1613
|
+
Object.defineProperty(inherited, field, {
|
|
1614
|
+
value,
|
|
1615
|
+
enumerable: true,
|
|
1616
|
+
configurable: true,
|
|
1617
|
+
writable: true
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
const assembled = {
|
|
1622
|
+
...row,
|
|
1623
|
+
payload: JSON.parse(JSON.stringify({
|
|
1624
|
+
...inherited,
|
|
1625
|
+
...row.payload
|
|
1626
|
+
}))
|
|
1627
|
+
};
|
|
1628
|
+
active.delete(id);
|
|
1629
|
+
cache.set(id, assembled);
|
|
1630
|
+
return assembled;
|
|
1631
|
+
};
|
|
1632
|
+
return visit(entityId);
|
|
1633
|
+
}
|
|
1634
|
+
/** Resolve a field's declaring entity after validating the entire composition. */
|
|
1635
|
+
function resolveEntityFieldOwner(rows, entityId, field) {
|
|
1636
|
+
assembleEntityContent(rows, entityId);
|
|
1637
|
+
const byId = new Map(rows.entities.map((row) => [row.entityId, row]));
|
|
1638
|
+
const find = (id) => {
|
|
1639
|
+
const row = byId.get(id);
|
|
1640
|
+
if (Object.hasOwn(row.payload, field)) return id;
|
|
1641
|
+
if (field === "baseEntityIds") return void 0;
|
|
1642
|
+
for (const baseId of variantBaseEntityIds(row)) {
|
|
1643
|
+
const owner = find(baseId);
|
|
1644
|
+
if (owner !== void 0) return owner;
|
|
1645
|
+
}
|
|
1646
|
+
};
|
|
1647
|
+
return find(entityId) ?? entityId;
|
|
1648
|
+
}
|
|
1649
|
+
/** Patch assembled fields without copying inherited fields into the variant's stored payload. */
|
|
1650
|
+
function updateEntityFields(rows, entityId, fields) {
|
|
1651
|
+
assembleEntityContent(rows, entityId);
|
|
1652
|
+
if (!isJsonObject(fields) || Object.hasOwn(fields, "entityId") || Object.hasOwn(fields, "entityKind")) throw new ScriptCompositionError("invalid_bases", entityId, "Field updates require JSON without reserved identity fields");
|
|
1653
|
+
const updates = /* @__PURE__ */ new Map();
|
|
1654
|
+
for (const [field, value] of Object.entries(fields)) {
|
|
1655
|
+
const ownerId = resolveEntityFieldOwner(rows, entityId, field);
|
|
1656
|
+
const owner = updates.get(ownerId) ?? rows.entities.find((row) => row.entityId === ownerId);
|
|
1657
|
+
updates.set(ownerId, {
|
|
1658
|
+
...owner,
|
|
1659
|
+
payload: {
|
|
1660
|
+
...owner.payload,
|
|
1661
|
+
[field]: value
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1665
|
+
return [...updates.values()].map((row) => JSON.parse(JSON.stringify(row)));
|
|
1546
1666
|
}
|
|
1547
|
-
/**
|
|
1548
|
-
* Resolve the one AudioScript a variant composes. Relations are queried from
|
|
1549
|
-
* both endpoints, so persisted endpoint positions do not matter.
|
|
1550
|
-
*/
|
|
1667
|
+
/** Find the actual AudioScript text owner through direct variant bases. */
|
|
1551
1668
|
function findComposedAudioScript(rows, variantEntityId, variantKind) {
|
|
1552
|
-
const
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
const
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1669
|
+
const variant = requireEntityKind(rows, variantEntityId, variantKind);
|
|
1670
|
+
assembleEntityContent(rows, variantEntityId);
|
|
1671
|
+
const sources = /* @__PURE__ */ new Map();
|
|
1672
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1673
|
+
const visit = (row) => {
|
|
1674
|
+
for (const id of variantBaseEntityIds(row)) {
|
|
1675
|
+
if (seen.has(id)) continue;
|
|
1676
|
+
seen.add(id);
|
|
1677
|
+
const base = rows.entities.find((candidate) => candidate.entityId === id);
|
|
1678
|
+
if (base.entityKind === "audio-script") sources.set(id, assembleEntityContent(rows, id));
|
|
1679
|
+
else visit(base);
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
visit(variant);
|
|
1683
|
+
if (sources.size !== 1) throw new ScriptCompositionError(sources.size === 0 ? "composition_missing" : "composition_ambiguous", variantEntityId, `${variantKind} "${variantEntityId}" baseEntityIds must resolve one AudioScript text owner, got ${sources.size}`);
|
|
1684
|
+
return [...sources.values()][0];
|
|
1561
1685
|
}
|
|
1562
1686
|
/** Join the whole AudioScript text in segment order. */
|
|
1563
1687
|
function assembleScriptText(script) {
|
|
@@ -1574,16 +1698,15 @@ function isScriptSegment(value) {
|
|
|
1574
1698
|
const segment = value;
|
|
1575
1699
|
return typeof segment.segmentId === "string" && segment.segmentId.trim() !== "" && typeof segment.text === "string" && (segment.language === void 0 || typeof segment.language === "string");
|
|
1576
1700
|
}
|
|
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
|
-
*/
|
|
1701
|
+
/** Assemble selected text after base-field validation and explicit variant overrides. */
|
|
1583
1702
|
function assembleCaptionContent(rows, captionEntityId) {
|
|
1584
|
-
|
|
1703
|
+
requireEntityKind(rows, captionEntityId, "caption");
|
|
1704
|
+
const caption = assembleEntityContent(rows, captionEntityId);
|
|
1585
1705
|
const script = findComposedAudioScript(rows, captionEntityId, "caption");
|
|
1586
|
-
const segments = selectAudioScriptSegments(
|
|
1706
|
+
const segments = selectAudioScriptSegments({
|
|
1707
|
+
...script,
|
|
1708
|
+
payload: caption.payload
|
|
1709
|
+
}, captionSelections(caption));
|
|
1587
1710
|
return {
|
|
1588
1711
|
caption,
|
|
1589
1712
|
audioScript: script,
|
|
@@ -1596,9 +1719,13 @@ function assembleCaptionContent(rows, captionEntityId) {
|
|
|
1596
1719
|
* AudioScript's base text plus the variant's own phoneme and prosody fields.
|
|
1597
1720
|
*/
|
|
1598
1721
|
function assemblePhoneticScriptContent(rows, phoneticScriptEntityId) {
|
|
1599
|
-
|
|
1722
|
+
requireEntityKind(rows, phoneticScriptEntityId, "phonetic-script");
|
|
1723
|
+
const phoneticScript = assembleEntityContent(rows, phoneticScriptEntityId);
|
|
1600
1724
|
const audioScript = findComposedAudioScript(rows, phoneticScriptEntityId, "phonetic-script");
|
|
1601
|
-
const segments = scriptSegments(
|
|
1725
|
+
const segments = scriptSegments({
|
|
1726
|
+
...audioScript,
|
|
1727
|
+
payload: phoneticScript.payload
|
|
1728
|
+
});
|
|
1602
1729
|
return {
|
|
1603
1730
|
phoneticScript,
|
|
1604
1731
|
audioScript,
|
|
@@ -1641,16 +1768,15 @@ function requireEntityKind(rows, entityIdValue, entityKind) {
|
|
|
1641
1768
|
return entity;
|
|
1642
1769
|
}
|
|
1643
1770
|
//#endregion
|
|
1644
|
-
//#region ../medeo-dsl/src/
|
|
1645
|
-
function
|
|
1646
|
-
|
|
1647
|
-
}
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
return value;
|
|
1771
|
+
//#region ../medeo-dsl/src/rows.ts
|
|
1772
|
+
function entityToRow(entity) {
|
|
1773
|
+
const { entityId, entityKind, ...payload } = entity;
|
|
1774
|
+
if (!isJsonObject(payload)) throw new Error(`Entity "${entityId}" payload must contain only JSON values`);
|
|
1775
|
+
return {
|
|
1776
|
+
entityId,
|
|
1777
|
+
entityKind,
|
|
1778
|
+
payload
|
|
1779
|
+
};
|
|
1654
1780
|
}
|
|
1655
1781
|
//#endregion
|
|
1656
1782
|
//#region ../medeo-dsl/src/invariants.ts
|
|
@@ -1671,6 +1797,19 @@ function validateMediaAssetIdentity(entity, index) {
|
|
|
1671
1797
|
function validateEntityRelationSet(entityRefs, index, options) {
|
|
1672
1798
|
const { entities, issues } = collectRelatedEntities(entityRefs, index);
|
|
1673
1799
|
const entityIds = new Set(entities.map((entity) => entity.entityId));
|
|
1800
|
+
const rows = {
|
|
1801
|
+
entities: entities.map((entity) => entityToRow(entity.current())),
|
|
1802
|
+
relations: []
|
|
1803
|
+
};
|
|
1804
|
+
for (const entity of entities) try {
|
|
1805
|
+
assembleEntityContent(rows, entity.entityId);
|
|
1806
|
+
} catch (error) {
|
|
1807
|
+
issues.push({
|
|
1808
|
+
code: "invalid_variant_composition",
|
|
1809
|
+
entityId: entity.entityId,
|
|
1810
|
+
message: error instanceof Error ? error.message : "Invalid variant composition"
|
|
1811
|
+
});
|
|
1812
|
+
}
|
|
1674
1813
|
for (const entity of entities) {
|
|
1675
1814
|
const current = entity.current();
|
|
1676
1815
|
const entityIssues = validateEntity(entity, entityIds);
|
|
@@ -1691,8 +1830,8 @@ function validateEntityRelationSet(entityRefs, index, options) {
|
|
|
1691
1830
|
issues.push(...validateClipPlacement(entity, index));
|
|
1692
1831
|
}
|
|
1693
1832
|
if (current.entityKind === "axvideo") issues.push(...validateAXVideoAdmission(entity, index));
|
|
1694
|
-
if (current.entityKind === "caption") issues.push(...validateCaptionComposition(entity, index));
|
|
1695
|
-
if (current.entityKind === "phonetic-script") issues.push(...validatePhoneticComposition(entity, index));
|
|
1833
|
+
if (current.entityKind === "caption") issues.push(...validateCaptionComposition(entity, index, entities));
|
|
1834
|
+
if (current.entityKind === "phonetic-script") issues.push(...validatePhoneticComposition(entity, index, entities));
|
|
1696
1835
|
issues.push(...validateSequenceComposition(entity));
|
|
1697
1836
|
}
|
|
1698
1837
|
issues.push(...validateClipAnchorCycles(entities, index));
|
|
@@ -1795,60 +1934,32 @@ function validateAXVideoAdmission(axVideo, index) {
|
|
|
1795
1934
|
message: "AXVideo must have exactly one live AXVideo-Marker Relation"
|
|
1796
1935
|
}];
|
|
1797
1936
|
}
|
|
1798
|
-
/**
|
|
1799
|
-
|
|
1800
|
-
|
|
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");
|
|
1937
|
+
/** Validate a Caption against the complete entity set, including its directly held bases. */
|
|
1938
|
+
function validateCaptionComposition(caption, index, entities = []) {
|
|
1939
|
+
return validateVariantComposition(caption, index, entities, "caption");
|
|
1806
1940
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
return validateVariantComposition(phonetic, index, "phonetic-script", "phonetic-script-composition", "phonetic_script_composition_required");
|
|
1941
|
+
function validatePhoneticComposition(phonetic, index, entities = []) {
|
|
1942
|
+
return validateVariantComposition(phonetic, index, entities, "phonetic-script");
|
|
1810
1943
|
}
|
|
1811
|
-
function validateVariantComposition(variant, index,
|
|
1812
|
-
const relations = [...index.relationsOf(variant)];
|
|
1944
|
+
function validateVariantComposition(variant, index, entities, kind) {
|
|
1813
1945
|
const issues = [];
|
|
1814
|
-
|
|
1815
|
-
if (variantKind === "caption" && physicalEdges.length > 0) issues.push({
|
|
1946
|
+
if (kind === "caption" && ofKind([...index.relationsOf(variant)], "physical-asset").length > 0) issues.push({
|
|
1816
1947
|
code: "caption_physical_asset_forbidden",
|
|
1817
1948
|
entityId: variant.entityId,
|
|
1818
1949
|
message: "Caption text is composed from its AudioScript; Caption must not bind a Physical Asset"
|
|
1819
1950
|
});
|
|
1820
|
-
const
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
entityId: variant.entityId,
|
|
1825
|
-
message: `${variantKind} must have exactly one ${compositionKind} Relation to a live AudioScript`
|
|
1826
|
-
});
|
|
1827
|
-
return issues;
|
|
1828
|
-
}
|
|
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;
|
|
1951
|
+
const rows = {
|
|
1952
|
+
entities: collectRelatedEntities([...entities, variant], index).entities.map((ref) => entityToRow(ref.current())),
|
|
1953
|
+
relations: []
|
|
1954
|
+
};
|
|
1841
1955
|
try {
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
entityKind: "audio-script",
|
|
1845
|
-
payload: { segments: script.segments.map((segment) => ({ ...segment })) }
|
|
1846
|
-
}, selections);
|
|
1956
|
+
if (kind === "caption") assembleCaptionContent(rows, variant.entityId);
|
|
1957
|
+
else assemblePhoneticScriptContent(rows, variant.entityId);
|
|
1847
1958
|
} catch (error) {
|
|
1848
1959
|
issues.push({
|
|
1849
|
-
code: "
|
|
1960
|
+
code: kind === "caption" ? "caption_composition_required" : "phonetic_script_composition_required",
|
|
1850
1961
|
entityId: variant.entityId,
|
|
1851
|
-
message: error instanceof Error ? error.message : "Invalid
|
|
1962
|
+
message: error instanceof Error ? error.message : "Invalid variant composition"
|
|
1852
1963
|
});
|
|
1853
1964
|
}
|
|
1854
1965
|
return issues;
|
|
@@ -2123,7 +2234,6 @@ function validateVoicePayload(value, problems) {
|
|
|
2123
2234
|
if (voice.name !== void 0 && typeof voice.name !== "string") problems.push("voice.name must be a string when present");
|
|
2124
2235
|
}
|
|
2125
2236
|
function validateCaptionPayload(value, problems) {
|
|
2126
|
-
if (value.text !== void 0) problems.push("text is composed from the AudioScript; Caption must not store a text copy");
|
|
2127
2237
|
const selections = value.selections;
|
|
2128
2238
|
if (!Array.isArray(selections)) problems.push("selections must be a non-empty array of AudioScript segment selections");
|
|
2129
2239
|
else {
|
|
@@ -2180,8 +2290,7 @@ function validateRange(value, path, required, problems) {
|
|
|
2180
2290
|
}
|
|
2181
2291
|
/** Phonetic variants store pronunciation fields only; base text stays in the AudioScript. */
|
|
2182
2292
|
function validatePhoneticScriptPayload(value, problems) {
|
|
2183
|
-
if (value.
|
|
2184
|
-
if (value.segments !== void 0) problems.push("segments carry the base text owned by the AudioScript; PhoneticScript stores pronunciation fields only");
|
|
2293
|
+
if (value.segments !== void 0) validateScriptPayload(value, problems);
|
|
2185
2294
|
if (value.phonemeScript !== void 0 && (typeof value.phonemeScript !== "string" || value.phonemeScript.trim() === "")) problems.push("phonemeScript must be a non-empty string when present");
|
|
2186
2295
|
if (value.prosody !== void 0 && !isRecord(value.prosody)) problems.push("prosody must be an object when present");
|
|
2187
2296
|
}
|
|
@@ -2227,6 +2336,7 @@ function visitPeerEntityIdPaths(value, entityKind, parentPath, ancestors, paths)
|
|
|
2227
2336
|
if (Array.isArray(value)) for (const [index, item] of value.entries()) visitPeerEntityIdPaths(item, entityKind, `${parentPath}[${index}]`, ancestors, paths);
|
|
2228
2337
|
else for (const [key, child] of Object.entries(value)) {
|
|
2229
2338
|
const path = parentPath.length === 0 ? key : `${parentPath}.${key}`;
|
|
2339
|
+
if (parentPath.length === 0 && key === "baseEntityIds") continue;
|
|
2230
2340
|
if (!(parentPath.length === 0 && key === "entityId") && !isOwnedLocalIdPath(entityKind, path) && isEntityIdFieldName(key)) paths.push(path);
|
|
2231
2341
|
visitPeerEntityIdPaths(child, entityKind, path, ancestors, paths);
|
|
2232
2342
|
}
|
|
@@ -2246,7 +2356,7 @@ function visitPeerEntityValues(value, entityKind, ownEntityId, entityIds, path,
|
|
|
2246
2356
|
ancestors.add(value);
|
|
2247
2357
|
if (Array.isArray(value)) for (const [index, item] of value.entries()) visitPeerEntityValues(item, entityKind, ownEntityId, entityIds, `${path}[${index}]`, ancestors, paths);
|
|
2248
2358
|
else for (const [key, child] of Object.entries(value)) {
|
|
2249
|
-
if (path.length === 0 && (key === "entityId" || key === "entityKind")) continue;
|
|
2359
|
+
if (path.length === 0 && (key === "entityId" || key === "entityKind" || key === "baseEntityIds")) continue;
|
|
2250
2360
|
visitPeerEntityValues(child, entityKind, ownEntityId, entityIds, path.length === 0 ? key : `${path}.${key}`, ancestors, paths);
|
|
2251
2361
|
}
|
|
2252
2362
|
ancestors.delete(value);
|
|
@@ -2267,12 +2377,20 @@ function isOwnedLocalEntityValuePath(entityKind, path) {
|
|
|
2267
2377
|
if (isMediaAssetVariantKind(entityKind) && /^(?:external\.(?:system|key)|storageKey)$/.test(path)) return true;
|
|
2268
2378
|
if (entityKind === "voice" && /^voice\.(?:system|key|name)$/.test(path)) return true;
|
|
2269
2379
|
if (entityKind === "caption" && (path.startsWith("style.") || /^selections\[\d+\]\.segmentId$/.test(path))) return true;
|
|
2270
|
-
if (
|
|
2380
|
+
if ([
|
|
2381
|
+
"audio-script",
|
|
2382
|
+
"caption",
|
|
2383
|
+
"phonetic-script"
|
|
2384
|
+
].includes(entityKind) && /^segments\[\d+\]\.(?:segmentId|text|language)$/.test(path)) return true;
|
|
2271
2385
|
return false;
|
|
2272
2386
|
}
|
|
2273
2387
|
function isOwnedLocalIdPath(entityKind, path) {
|
|
2274
2388
|
if (path === "lifecycle.actorId") return true;
|
|
2275
|
-
if (
|
|
2389
|
+
if ([
|
|
2390
|
+
"audio-script",
|
|
2391
|
+
"caption",
|
|
2392
|
+
"phonetic-script"
|
|
2393
|
+
].includes(entityKind) && /^segments\[\d+\]\.segmentId$/.test(path)) return true;
|
|
2276
2394
|
if (entityKind === "caption" && /^selections\[\d+\]\.segmentId$/.test(path)) return true;
|
|
2277
2395
|
if (entityKind === "sequence-marker" && /^segmentRanges\[\d+\]\.segmentId$/.test(path)) return true;
|
|
2278
2396
|
if (entityKind === "asset" && /^(?:tracks\[\d+\]\.trackId|renditions\[\d+\]\.renditionId)$/.test(path)) return true;
|
|
@@ -2329,35 +2447,6 @@ function ofKind(relations, kind) {
|
|
|
2329
2447
|
return relations.filter((relation) => relation.kind === kind);
|
|
2330
2448
|
}
|
|
2331
2449
|
//#endregion
|
|
2332
|
-
//#region ../medeo-dsl/src/json-values.ts
|
|
2333
|
-
const nativeObjectConstructorSource = Function.prototype.toString.call(Object);
|
|
2334
|
-
function isJsonObject(value) {
|
|
2335
|
-
return isJsonValue(value, /* @__PURE__ */ new Set()) && !Array.isArray(value) && value !== null;
|
|
2336
|
-
}
|
|
2337
|
-
function isJsonValue(value, ancestors) {
|
|
2338
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
2339
|
-
if (typeof value === "number") return Number.isFinite(value);
|
|
2340
|
-
if (typeof value !== "object") return false;
|
|
2341
|
-
if (!Array.isArray(value) && !isPlainObject(value)) return false;
|
|
2342
|
-
if (ancestors.has(value)) return false;
|
|
2343
|
-
ancestors.add(value);
|
|
2344
|
-
const valid = Array.isArray(value) ? value.every((item) => isJsonValue(item, ancestors)) : Object.values(value).every((item) => isJsonValue(item, ancestors));
|
|
2345
|
-
ancestors.delete(value);
|
|
2346
|
-
return valid;
|
|
2347
|
-
}
|
|
2348
|
-
/** Recognize an ordinary object from any VM realm without admitting class instances. */
|
|
2349
|
-
function isPlainObject(value) {
|
|
2350
|
-
try {
|
|
2351
|
-
const prototype = Object.getPrototypeOf(value);
|
|
2352
|
-
if (prototype === null) return true;
|
|
2353
|
-
if (Object.getPrototypeOf(prototype) !== null) return false;
|
|
2354
|
-
const constructor = Object.getOwnPropertyDescriptor(prototype, "constructor")?.value;
|
|
2355
|
-
return typeof constructor === "function" && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === nativeObjectConstructorSource;
|
|
2356
|
-
} catch {
|
|
2357
|
-
return false;
|
|
2358
|
-
}
|
|
2359
|
-
}
|
|
2360
|
-
//#endregion
|
|
2361
2450
|
//#region ../medeo-dsl/src/relation-specs.ts
|
|
2362
2451
|
const timelineTrackRelationSpec = emptySpec("timeline-track", "timeline", "track");
|
|
2363
2452
|
const trackClipRelationSpec = emptySpec("track-clip", "track", "clip");
|
|
@@ -2380,15 +2469,6 @@ const generatedRelationSpec = Object.freeze({
|
|
|
2380
2469
|
validateEndpoints: (endpoints) => endpoints.every((endpoint) => isGeneratedMedia(endpoint.current())),
|
|
2381
2470
|
validateMetadata: isEmptyMetadata
|
|
2382
2471
|
});
|
|
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);
|
|
2392
2472
|
const captionAlignmentRelationSpec = Object.freeze({
|
|
2393
2473
|
kind: "caption-alignment",
|
|
2394
2474
|
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["caption"]), new Set(["audio", "voice"])),
|
|
@@ -2437,8 +2517,6 @@ const builtInRelationSpecs = Object.freeze([
|
|
|
2437
2517
|
markerTimelineRelationSpec,
|
|
2438
2518
|
physicalAssetRelationSpec,
|
|
2439
2519
|
generatedRelationSpec,
|
|
2440
|
-
phoneticScriptCompositionRelationSpec,
|
|
2441
|
-
captionCompositionRelationSpec,
|
|
2442
2520
|
captionAlignmentRelationSpec,
|
|
2443
2521
|
clipAnchorRelationSpec,
|
|
2444
2522
|
phoneticScriptRenderRelationSpec,
|
|
@@ -2481,9 +2559,6 @@ function isAssetBinding(value) {
|
|
|
2481
2559
|
const orderingKey = /(order|ordinal|position|rank|index|z[_-]?index)/i;
|
|
2482
2560
|
return Object.keys(value).every((key) => !orderingKey.test(key));
|
|
2483
2561
|
}
|
|
2484
|
-
function isSegmentAlignmentMetadata(value) {
|
|
2485
|
-
return isJsonObject(value) && Object.hasOwn(value, "segmentAlignment");
|
|
2486
|
-
}
|
|
2487
2562
|
function isCaptionAlignmentMetadata(value) {
|
|
2488
2563
|
return isJsonObject(value) && Object.hasOwn(value, "alignment");
|
|
2489
2564
|
}
|
|
@@ -2669,7 +2744,13 @@ function decodeEntityRelationRows(rows, options) {
|
|
|
2669
2744
|
const entitiesById = /* @__PURE__ */ new Map();
|
|
2670
2745
|
const extensionEntityKinds = new Set(options.entityKinds ?? []);
|
|
2671
2746
|
for (const row of rows.entities) {
|
|
2672
|
-
|
|
2747
|
+
let entity = decodeEntityRow(row, extensionEntityKinds, issues);
|
|
2748
|
+
if (entity != null) try {
|
|
2749
|
+
entity = decodeEntityRow(assembleEntityContent(rows, row.entityId), extensionEntityKinds, issues);
|
|
2750
|
+
} catch (error) {
|
|
2751
|
+
issues.push(errorMessage(error));
|
|
2752
|
+
continue;
|
|
2753
|
+
}
|
|
2673
2754
|
if (entity == null) continue;
|
|
2674
2755
|
const ref = createEntityRef(entity);
|
|
2675
2756
|
if (entitiesById.has(ref.entityId)) {
|
|
@@ -2849,9 +2930,9 @@ var EntityProjectionGraph = class {
|
|
|
2849
2930
|
timeline;
|
|
2850
2931
|
constructor(rows) {
|
|
2851
2932
|
this.rows = rows;
|
|
2852
|
-
decodeEntityRelationRows(rows, { compareMarkerPoints: (_marker, _range, left, right) => finite(left, "range point") - finite(right, "range point") });
|
|
2853
|
-
this.entities = new Map(
|
|
2854
|
-
const roots =
|
|
2933
|
+
const decoded = decodeEntityRelationRows(rows, { compareMarkerPoints: (_marker, _range, left, right) => finite(left, "range point") - finite(right, "range point") });
|
|
2934
|
+
this.entities = new Map([...decoded.entitiesById.values()].map((ref) => [String(ref.entityId), entityToRow(ref.current())]));
|
|
2935
|
+
const roots = [...this.entities.values()].filter((row) => row.entityKind === "timeline");
|
|
2855
2936
|
if (roots.length !== 1) fail("compatibility projection requires exactly one Timeline");
|
|
2856
2937
|
this.timeline = roots[0];
|
|
2857
2938
|
}
|
|
@@ -3539,4 +3620,4 @@ function createPlainMemoryAdapter(document, options) {
|
|
|
3539
3620
|
return new PlainMemoryAdapter(document, options);
|
|
3540
3621
|
}
|
|
3541
3622
|
//#endregion
|
|
3542
|
-
export {
|
|
3623
|
+
export { isEmptyVideoClip as $, buildSpeechHostMap as A, ensureLaneTrack as B, variantBaseEntityIds as C, hasSequence as D, createRelationId as E, assertValidVideoDocument as F, arrangeMainTrackSeamlessly as G, laneTrackId as H, validateVideoDocument as I, recalculateTimelineDuration as J, fillMainTrackTimeGaps as K, partUnionSchema as L, fromVideoDocument as M, toVideoDocument as N, isMediaAssetVariantKind as O, VideoDocumentValidationError as P, TIMELINE_SKELETON_DURATION_MS as Q, videoDocumentSchema as R, updateEntityFields as S, createEntityId as T, solveVideoDocument as U, findLaneTrack as V, cascadeAfterVideoClipChanges as W, resolveSpeechOverlapByShiftingVideos as X, resolveAllSpeechOverlaps as Y, syncAggregatedClipsTimePosition as Z, assembleEntityContent as _, applyEntityTimelineProjection as a, effectiveVideoClipDurationMs as at, findComposedAudioScript as b, writeVideoDocumentToDraft as c, recordEntries as ct, EntityProjectionGraph as d, bytesToBase64 as dt, partDurationMs as et, resolveEntityTimelineLayout as f, assembleCaptionContent as g, ScriptCompositionError as h, MirrorVideoDocumentAdapter as i, VIDEO_DOCUMENT_SCHEMA_VERSION as it, derivePositionFromAbs as j, buildInitialVideoDocument as k, readVideoDocumentFromDraft as l, videoDocumentMirrorSchema as lt, decodeEntityRelationRows as m, createPlainMemoryAdapter as n, DEFAULT_UNIT_TIME_MS as nt, createMirrorVideoDocument as o, speedOf as ot, EntityTimelineProjectionError as p, reassignSpeechesToVideoClipsByTime as q, generatePartId as r, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION as rt, createMirrorVideoDocumentAdapter as s, partUnionToDraft as st, PlainMemoryAdapter as t, safeDurationMs as tt, projectEntityTimeline as u, base64ToBytes as ut, assemblePhoneticScriptContent as v, isJsonObject as w, selectAudioScriptSegments as x, assembleScriptText as y, LANE_KINDS_IN_STACK_ORDER as z };
|
|
@@ -914,7 +914,7 @@ interface CaptionTextRange extends JsonObject {
|
|
|
914
914
|
* One ordered entry of the Caption's segment selection. `segmentId` quotes the
|
|
915
915
|
* composed AudioScript's own stable segment identity — a local id quoted by the
|
|
916
916
|
* variant, never a peer Entity reference. Text itself is never copied here;
|
|
917
|
-
* complete Caption content is assembled
|
|
917
|
+
* complete Caption content is assembled through its direct baseEntityIds.
|
|
918
918
|
* The optional `textRange` narrows one Segment to an intra-Segment sub-span
|
|
919
919
|
* (intra-segment re-segmentation); without it the whole Segment text is selected.
|
|
920
920
|
*/
|
|
@@ -924,7 +924,7 @@ type CaptionSegmentSelection = JsonObject & {
|
|
|
924
924
|
};
|
|
925
925
|
//#endregion
|
|
926
926
|
//#region ../medeo-dsl/src/relations.d.ts
|
|
927
|
-
type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'physical-asset' | 'generated' | '
|
|
927
|
+
type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'physical-asset' | 'generated' | 'caption-alignment' | 'clip-anchor' | 'phonetic-script-render' | 'audio-script-source' | 'audio-script-marker';
|
|
928
928
|
type RelationKind = KnownRelationKind | (string & {});
|
|
929
929
|
type RelationTrace = JsonObject;
|
|
930
930
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as index_d_exports } from "./index-CMa6ZCtX.js";
|
|
2
|
-
import { $ as VoiceDescriptor, A as generatePartId, At as effectiveVideoClipDurationMs, B as ResolvedEntityClipPlacement, C as PlannedSemanticOpKind, Ct as VideoClipPart, D as SnapshotReadable, Dt as VideoDocumentValidationIssueCode, E as SchemaValidator, Et as VideoDocumentValidationIssue, F as videoDocumentMirrorSchema, Ft as PartAggregation, G as EntityTimelineProjectionError, H as ResolvedEntityTrack, I as VideoDocumentValidationError, It as SpeedShift, J as CaptionSegmentSelection, K as EntityRelationRows, L as assertValidVideoDocument, Lt as Timeline$1, M as TrackItemDraft, Mt as Attachment, N as VideoDocumentDraft, Nt as CaptionPart$1, O as ValidationError, Ot as VideoDraft, P as VideoDocumentMirrorSchema, Pt as CaptionStyle, Q as SequenceRange, R as validateVideoDocument, Rt as Track$1, S as ImplementedSemanticOpKind, St as VIDEO_DOCUMENT_SCHEMA_VERSION, T as isImplementedSemanticOpKind, Tt as VideoDocumentSchemaVersion, U as resolveEntityTimelineLayout, V as ResolvedEntityTimelineLayout, W as projectEntityTimeline, X as ScriptTextSegment, Y as CaptionStyleFields, Z as SequenceDuration, _ as SemanticEditor, _t as SpeechPart, a as PlainMemoryAdapter, at as DerivedItemPosition, b as TransactAudit, bt as TrackItem, c as MirrorVideoDocumentAdapter, ct as derivePositionFromAbs, d as createMirrorVideoDocument, dt as BgmPart, et as JsonObject, f as createMirrorVideoDocumentAdapter, ft as CaptionPart, g as SemanticDocumentAdapter, gt as PartUnion, h as OpActor, ht as PartKind, i as JournalEntry, it as buildInitialVideoDocument, j as TrackDraft, jt as speedOf, k as PartIdFactory, kt as VideoDraftPartUnion, l as MirrorVideoDocumentOptions, lt as fromVideoDocument, m as CommitOptions, mt as ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, n as videoDocumentSchema, nt as EntityId, o as PlainMemoryAdapterOptions, ot as SpeechHostMap, p as writeVideoDocumentToDraft, pt as DEFAULT_UNIT_TIME_MS, q as EntityRow, r as readVideoDocumentFromDraft, rt as InitialDocumentFacts, s as createPlainMemoryAdapter, st as buildSpeechHostMap, t as partUnionSchema, tt as JsonValue, u as applyEntityTimelineProjection, ut as toVideoDocument, v as SemanticOpInput, vt as Timeline, w as SemanticOpKind, wt as VideoDocument, x as IMPLEMENTED_SEMANTIC_OP_KINDS, xt as TrackItemTimePosition, y as SemanticOpName, yt as Track, z as EntityTimelineTrackRole, zt as TrackItem$1 } from "./index-
|
|
2
|
+
import { $ as VoiceDescriptor, A as generatePartId, At as effectiveVideoClipDurationMs, B as ResolvedEntityClipPlacement, C as PlannedSemanticOpKind, Ct as VideoClipPart, D as SnapshotReadable, Dt as VideoDocumentValidationIssueCode, E as SchemaValidator, Et as VideoDocumentValidationIssue, F as videoDocumentMirrorSchema, Ft as PartAggregation, G as EntityTimelineProjectionError, H as ResolvedEntityTrack, I as VideoDocumentValidationError, It as SpeedShift, J as CaptionSegmentSelection, K as EntityRelationRows, L as assertValidVideoDocument, Lt as Timeline$1, M as TrackItemDraft, Mt as Attachment, N as VideoDocumentDraft, Nt as CaptionPart$1, O as ValidationError, Ot as VideoDraft, P as VideoDocumentMirrorSchema, Pt as CaptionStyle, Q as SequenceRange, R as validateVideoDocument, Rt as Track$1, S as ImplementedSemanticOpKind, St as VIDEO_DOCUMENT_SCHEMA_VERSION, T as isImplementedSemanticOpKind, Tt as VideoDocumentSchemaVersion, U as resolveEntityTimelineLayout, V as ResolvedEntityTimelineLayout, W as projectEntityTimeline, X as ScriptTextSegment, Y as CaptionStyleFields, Z as SequenceDuration, _ as SemanticEditor, _t as SpeechPart, a as PlainMemoryAdapter, at as DerivedItemPosition, b as TransactAudit, bt as TrackItem, c as MirrorVideoDocumentAdapter, ct as derivePositionFromAbs, d as createMirrorVideoDocument, dt as BgmPart, et as JsonObject, f as createMirrorVideoDocumentAdapter, ft as CaptionPart, g as SemanticDocumentAdapter, gt as PartUnion, h as OpActor, ht as PartKind, i as JournalEntry, it as buildInitialVideoDocument, j as TrackDraft, jt as speedOf, k as PartIdFactory, kt as VideoDraftPartUnion, l as MirrorVideoDocumentOptions, lt as fromVideoDocument, m as CommitOptions, mt as ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, n as videoDocumentSchema, nt as EntityId, o as PlainMemoryAdapterOptions, ot as SpeechHostMap, p as writeVideoDocumentToDraft, pt as DEFAULT_UNIT_TIME_MS, q as EntityRow, r as readVideoDocumentFromDraft, rt as InitialDocumentFacts, s as createPlainMemoryAdapter, st as buildSpeechHostMap, t as partUnionSchema, tt as JsonValue, u as applyEntityTimelineProjection, ut as toVideoDocument, v as SemanticOpInput, vt as Timeline, w as SemanticOpKind, wt as VideoDocument, x as IMPLEMENTED_SEMANTIC_OP_KINDS, xt as TrackItemTimePosition, y as SemanticOpName, yt as Track, z as EntityTimelineTrackRole, zt as TrackItem$1 } from "./index-Dxxu0Mi1.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";
|
|
@@ -179,13 +179,8 @@ interface MengineEventStreamOptions {
|
|
|
179
179
|
declare function readMengineEventStream(options: MengineEventStreamOptions): Promise<void>;
|
|
180
180
|
//#endregion
|
|
181
181
|
//#region ../medeo-dsl/src/composition.d.ts
|
|
182
|
-
type ScriptCompositionIssueCode = 'composition_missing' | 'composition_ambiguous' | 'composition_dangling' | 'unknown_segment' | 'empty_selection' | 'invalid_script' | 'invalid_selection';
|
|
183
|
-
/**
|
|
184
|
-
* Raised when a variant's complete content cannot be assembled from its
|
|
185
|
-
* required composition Relation. Assembly never falls back to variant-local
|
|
186
|
-
* text: a missing, ambiguous, or dangling source is an error, not an empty
|
|
187
|
-
* read.
|
|
188
|
-
*/
|
|
182
|
+
type ScriptCompositionIssueCode = 'field_conflict' | 'composition_cycle' | 'invalid_bases' | 'composition_missing' | 'composition_ambiguous' | 'composition_dangling' | 'unknown_segment' | 'empty_selection' | 'invalid_script' | 'invalid_selection';
|
|
183
|
+
/** Assembly fails explicitly when declared bases cannot provide valid, unambiguous content. */
|
|
189
184
|
declare class ScriptCompositionError extends Error {
|
|
190
185
|
readonly code: ScriptCompositionIssueCode;
|
|
191
186
|
readonly entityId: EntityId;
|
|
@@ -207,19 +202,13 @@ interface AssembledPhoneticScriptContent {
|
|
|
207
202
|
/** Complete base text owned by the AudioScript. */
|
|
208
203
|
readonly text: string;
|
|
209
204
|
}
|
|
210
|
-
/**
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
*/
|
|
205
|
+
/** Validate all base providers before applying explicit own fields; ordering cannot resolve ambiguity. */
|
|
206
|
+
declare function assembleEntityContent(rows: EntityRelationRows, entityId: EntityId): EntityRow;
|
|
207
|
+
/** Find the actual AudioScript text owner through direct variant bases. */
|
|
214
208
|
declare function findComposedAudioScript(rows: EntityRelationRows, variantEntityId: EntityId, variantKind: 'caption' | 'phonetic-script'): EntityRow<'audio-script'>;
|
|
215
209
|
/** Join the whole AudioScript text in segment order. */
|
|
216
210
|
declare function assembleScriptText(script: EntityRow<'audio-script'>): string;
|
|
217
|
-
/**
|
|
218
|
-
* Assemble the complete Caption content from its AudioScript: the selected
|
|
219
|
-
* segments in selection order, joined as display text. The Caption payload
|
|
220
|
-
* never carries text, so a broken composition fails here instead of silently
|
|
221
|
-
* rendering an empty caption.
|
|
222
|
-
*/
|
|
211
|
+
/** Assemble selected text after base-field validation and explicit variant overrides. */
|
|
223
212
|
declare function assembleCaptionContent(rows: EntityRelationRows, captionEntityId: EntityId): AssembledCaptionContent;
|
|
224
213
|
/**
|
|
225
214
|
* Assemble the complete Phonetic Script content for TTS: the composed
|
|
@@ -339,6 +328,8 @@ interface DeleteClipTreeInput {
|
|
|
339
328
|
interface VoiceoverCaptionFact {
|
|
340
329
|
/** Stable placed caption identity supplied by the materialized side effect. */
|
|
341
330
|
readonly captionClipEntityId: string;
|
|
331
|
+
/** Directly held bases; includes the AudioScript used by the Voice. */
|
|
332
|
+
readonly baseEntityIds: readonly string[];
|
|
342
333
|
/** Ordered selection of AudioScript segments; caption text is never passed inline. */
|
|
343
334
|
readonly selections: readonly CaptionSegmentSelection[];
|
|
344
335
|
readonly startMs: number;
|
|
@@ -427,7 +418,7 @@ interface VoiceoverTakeResult {
|
|
|
427
418
|
readonly voiceEntityId: string;
|
|
428
419
|
/** The pronunciation variant the Voice was rendered from. */
|
|
429
420
|
readonly phoneticScriptEntityId: string;
|
|
430
|
-
/** The base-text owner resolved
|
|
421
|
+
/** The base-text owner resolved from the PhoneticScript baseEntityIds. */
|
|
431
422
|
readonly audioScriptEntityId: string;
|
|
432
423
|
readonly captionClipEntityIds: readonly string[];
|
|
433
424
|
}
|
|
@@ -460,8 +451,8 @@ interface InsertCaptionClipInput {
|
|
|
460
451
|
readonly timelineEntityId: string;
|
|
461
452
|
/** Stable placed caption identity, distinct from the Caption content identity. */
|
|
462
453
|
readonly captionClipEntityId?: string;
|
|
463
|
-
/** Existing
|
|
464
|
-
readonly
|
|
454
|
+
/** Existing bases composed by this variant; includes an AudioScript text owner. */
|
|
455
|
+
readonly baseEntityIds: readonly string[];
|
|
465
456
|
/** Ordered selection of the AudioScript segments this Caption displays. */
|
|
466
457
|
readonly selections: readonly CaptionSegmentSelection[];
|
|
467
458
|
/** Intrinsic cue length of the Caption entity itself; display comes from the placement. */
|
|
@@ -549,8 +540,8 @@ declare class EntityTimelineEditor {
|
|
|
549
540
|
patchCaptionStyle(input: PatchCaptionStyleInput): void;
|
|
550
541
|
/**
|
|
551
542
|
* Place a Caption as a composed variant of an existing AudioScript: the
|
|
552
|
-
* entity stores
|
|
553
|
-
* Sequence
|
|
543
|
+
* entity stores baseEntityIds, selection, optional style, and inherent cue-bounded
|
|
544
|
+
* Sequence. This helper does not copy base text. The Clip and its display Marker describe this use;
|
|
554
545
|
* moving or stretching the returned Clip later changes the Clip/Marker,
|
|
555
546
|
* never the Caption entity or the AudioScript.
|
|
556
547
|
*/
|
|
@@ -563,7 +554,7 @@ declare class EntityTimelineEditor {
|
|
|
563
554
|
private ensurePhoneticRender;
|
|
564
555
|
private reconcileVoiceoverCaptions;
|
|
565
556
|
private ensureRoleTrackForClip;
|
|
566
|
-
private
|
|
557
|
+
private replaceCaptionAlignment;
|
|
567
558
|
/**
|
|
568
559
|
* Remove one placed Caption use. The composed AudioScript outlives the
|
|
569
560
|
* caption: it may anchor further captions and remains the text owner.
|
|
@@ -651,6 +642,17 @@ declare function migrateLegacyTimelineToEntities(legacy: VideoDocument, assetFac
|
|
|
651
642
|
/** Server gate: a cutover may change representation, never the existing render facts. */
|
|
652
643
|
declare function assertEntityProjectionPreservesLegacy(legacy: VideoDocument, projection: VideoDocument, rows: EntityRelationRows): void;
|
|
653
644
|
//#endregion
|
|
645
|
+
//#region src/entity-editor/caption-content.d.ts
|
|
646
|
+
interface CaptionContentInput {
|
|
647
|
+
readonly contentEntityId: string;
|
|
648
|
+
readonly audioScriptEntityId: string;
|
|
649
|
+
readonly text: string;
|
|
650
|
+
readonly selections?: readonly CaptionSegmentSelection[];
|
|
651
|
+
readonly durationMs: number;
|
|
652
|
+
}
|
|
653
|
+
/** Author Caption content from semantic intent; callers never reconcile variant bases or assembled fields. */
|
|
654
|
+
declare function prepareCaptionContent(rows: EntityRelationRows, input: CaptionContentInput): EntityRow<'caption'>;
|
|
655
|
+
//#endregion
|
|
654
656
|
//#region src/editor/journal.d.ts
|
|
655
657
|
/**
|
|
656
658
|
* Wire a plain-memory adapter + editor that share a recording id factory, so
|
|
@@ -1555,4 +1557,4 @@ declare function hostForAbsMs(ranges: MainClipRange[], absMs: number): MainClipR
|
|
|
1555
1557
|
*/
|
|
1556
1558
|
declare function relativePositionForAbs(ranges: MainClipRange[], absMs: number): TrackItemTimePosition;
|
|
1557
1559
|
//#endregion
|
|
1558
|
-
export { type Aggregation, type AssembledCaptionContent, type AssembledPhoneticScriptContent, type Attachment, type AudioMediaAssetFact, type BgmPart, type CaptionPart, type CaptionSegmentSelection, type CaptionStyle, type ClipEntityId, type ClipPlacement, type CommitOptions, DEFAULT_UNIT_TIME_MS, type DeleteBgmInput, type DeleteClipInput, type DeleteClipTreeInput, type DeleteVoiceoverInput, type DerivedItemPosition, type DocStorageLike, type DocVersionMark, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, type EditorFoundation, type EntityGraphCommitOptions, EntityGraphHttpClient, type EntityGraphState, EntityTimelineEditor, type EntityTimelineIdFactory, EntityTimelineProjectionError, type EntityTimelineTrackRole, IMPLEMENTED_SEMANTIC_OP_KINDS, type ImageMediaAssetFact, type ImplementedSemanticOpKind, type ImportedMediaAsset, type InitialDocumentFacts, type InsertCaptionClipInput, type InsertClipInput, type InsertMediaClipInput, type InsertMediaClipsInput, type InsertPlacedClipInput, type JournalEntry, LANE_KINDS_IN_STACK_ORDER, type LaneKind, type LinearClipSpeed, type MainClipRange, type MakeEmptyPart, ManualSyncDoc, type ManualSyncDocOptions, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type MediaAssetFact, type MediaClipInsertion, 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 MoveClipInput, type MoveClipsToStartsInput, type MoveSequentialClipsInput, type MoveVoiceoverInput, type OpActor, type PartAggregation, type PartIdFactory, type PartKind, type PartUnion, type PatchCaptionStyleInput, PlainMemoryAdapter, type PlainMemoryAdapterOptions, type PlannedSemanticOpKind, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, type ReplaceClipContentInput, type ReplaceMediaClipInput, type ReplaceSequentialClipsInput, type ReplacementMediaClipInput, type ResolvedEntityClipPlacement, type ResolvedEntityTimelineLayout, type ResolvedEntityTrack, SchemaValidator, ScriptCompositionError, type SemanticDocumentAdapter, SemanticEditor, type SemanticOpInput, type SemanticOpKind, type SemanticOpName, type SequentialClipAnchor, type SetBgmInput, type SetCaptionVisibilityInput, type SetClipPlacementInput, type SetClipSpeedInput, type SetClipVolumeInput, 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, type TrimClipInput, type UpdateClipInput, type UpdateClipMarkerInput, 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 VideoMediaAssetFact, type VisualMediaAssetFact, type VoiceMediaAssetFact, type VoiceoverCaptionFact, type VoiceoverTakeInput, type VoiceoverTakeResult, type WaitForServerAckOptions, applyEntityTimelineProjection, arrangeMainTrackSeamlessly, assembleCaptionContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, projectEntityTimeline, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveSpeechOverlapByShiftingVideos, safeDurationMs, index_d_exports as schemas, selectAudioScriptSegments, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
|
1560
|
+
export { type Aggregation, type AssembledCaptionContent, type AssembledPhoneticScriptContent, type Attachment, type AudioMediaAssetFact, type BgmPart, type CaptionContentInput, type CaptionPart, type CaptionSegmentSelection, type CaptionStyle, type ClipEntityId, type ClipPlacement, type CommitOptions, DEFAULT_UNIT_TIME_MS, type DeleteBgmInput, type DeleteClipInput, type DeleteClipTreeInput, type DeleteVoiceoverInput, type DerivedItemPosition, type DocStorageLike, type DocVersionMark, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, type EditorFoundation, type EntityGraphCommitOptions, EntityGraphHttpClient, type EntityGraphState, EntityTimelineEditor, type EntityTimelineIdFactory, EntityTimelineProjectionError, type EntityTimelineTrackRole, IMPLEMENTED_SEMANTIC_OP_KINDS, type ImageMediaAssetFact, type ImplementedSemanticOpKind, type ImportedMediaAsset, type InitialDocumentFacts, type InsertCaptionClipInput, type InsertClipInput, type InsertMediaClipInput, type InsertMediaClipsInput, type InsertPlacedClipInput, type JournalEntry, LANE_KINDS_IN_STACK_ORDER, type LaneKind, type LinearClipSpeed, type MainClipRange, type MakeEmptyPart, ManualSyncDoc, type ManualSyncDocOptions, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type MediaAssetFact, type MediaClipInsertion, 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 MoveClipInput, type MoveClipsToStartsInput, type MoveSequentialClipsInput, type MoveVoiceoverInput, type OpActor, type PartAggregation, type PartIdFactory, type PartKind, type PartUnion, type PatchCaptionStyleInput, PlainMemoryAdapter, type PlainMemoryAdapterOptions, type PlannedSemanticOpKind, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, type ReplaceClipContentInput, type ReplaceMediaClipInput, type ReplaceSequentialClipsInput, type ReplacementMediaClipInput, type ResolvedEntityClipPlacement, type ResolvedEntityTimelineLayout, type ResolvedEntityTrack, SchemaValidator, ScriptCompositionError, type SemanticDocumentAdapter, SemanticEditor, type SemanticOpInput, type SemanticOpKind, type SemanticOpName, type SequentialClipAnchor, type SetBgmInput, type SetCaptionVisibilityInput, type SetClipPlacementInput, type SetClipSpeedInput, type SetClipVolumeInput, 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, type TrimClipInput, type UpdateClipInput, type UpdateClipMarkerInput, 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 VideoMediaAssetFact, type VisualMediaAssetFact, type VoiceMediaAssetFact, type VoiceoverCaptionFact, type VoiceoverTakeInput, type VoiceoverTakeResult, type WaitForServerAckOptions, applyEntityTimelineProjection, arrangeMainTrackSeamlessly, assembleCaptionContent, assembleEntityContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, prepareCaptionContent, projectEntityTimeline, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveSpeechOverlapByShiftingVideos, safeDurationMs, index_d_exports as schemas, selectAudioScriptSegments, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as isEmptyVideoClip, A as buildSpeechHostMap, B as ensureLaneTrack, C as variantBaseEntityIds, D as hasSequence, E as createRelationId, F as assertValidVideoDocument, G as arrangeMainTrackSeamlessly, H as laneTrackId, I as validateVideoDocument, J as recalculateTimelineDuration, K as fillMainTrackTimeGaps, L as partUnionSchema, M as fromVideoDocument, N as toVideoDocument, O as isMediaAssetVariantKind, P as VideoDocumentValidationError, Q as TIMELINE_SKELETON_DURATION_MS, R as videoDocumentSchema, S as updateEntityFields, T as createEntityId, U as solveVideoDocument, V as findLaneTrack, W as cascadeAfterVideoClipChanges, X as resolveSpeechOverlapByShiftingVideos, Y as resolveAllSpeechOverlaps, Z as syncAggregatedClipsTimePosition, _ as assembleEntityContent, a as applyEntityTimelineProjection, at as effectiveVideoClipDurationMs, b as findComposedAudioScript, c as writeVideoDocumentToDraft, ct as recordEntries, d as EntityProjectionGraph, dt as bytesToBase64, et as partDurationMs, f as resolveEntityTimelineLayout, g as assembleCaptionContent, h as ScriptCompositionError, i as MirrorVideoDocumentAdapter, it as VIDEO_DOCUMENT_SCHEMA_VERSION, j as derivePositionFromAbs, k as buildInitialVideoDocument, l as readVideoDocumentFromDraft, lt as videoDocumentMirrorSchema, m as decodeEntityRelationRows, n as createPlainMemoryAdapter, nt as DEFAULT_UNIT_TIME_MS, o as createMirrorVideoDocument, ot as speedOf, p as EntityTimelineProjectionError, q as reassignSpeechesToVideoClipsByTime, r as generatePartId, rt as ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, s as createMirrorVideoDocumentAdapter, st as partUnionToDraft, t as PlainMemoryAdapter, tt as safeDurationMs, u as projectEntityTimeline, ut as base64ToBytes, v as assemblePhoneticScriptContent, w as isJsonObject, x as selectAudioScriptSegments, y as assembleScriptText, z as LANE_KINDS_IN_STACK_ORDER } from "./document-BLYcbv8E.js";
|
|
2
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";
|
|
@@ -616,8 +616,12 @@ function requireComposedAudioScript(rows, phoneticScriptEntityId) {
|
|
|
616
616
|
function captionSelections(selections) {
|
|
617
617
|
return structuredClone(selections);
|
|
618
618
|
}
|
|
619
|
-
function
|
|
620
|
-
|
|
619
|
+
function captionBaseIds(ids) {
|
|
620
|
+
if (!Array.isArray(ids) || ids.length === 0) throw new Error("Caption requires non-empty baseEntityIds");
|
|
621
|
+
return ids.map(createEntityId);
|
|
622
|
+
}
|
|
623
|
+
function assertCaptionScript(rows, captionId, scriptId) {
|
|
624
|
+
if (assembleCaptionContent(rows, captionId).audioScript.entityId !== scriptId) throw new Error("Voiceover Caption must compose the same AudioScript as the PhoneticScript");
|
|
621
625
|
}
|
|
622
626
|
const roleOrder = {
|
|
623
627
|
caption: 0,
|
|
@@ -1281,28 +1285,23 @@ var EntityTimelineEditor = class {
|
|
|
1281
1285
|
const track = findRoleTrack(draft, input.timelineEntityId, "caption");
|
|
1282
1286
|
if (track === void 0) return;
|
|
1283
1287
|
const patch = cloneJsonObject(input.style, "Caption style");
|
|
1288
|
+
const assembled = new EntityProjectionGraph(draft);
|
|
1284
1289
|
for (const clip of clipsOnTrack(draft, track.entityId)) {
|
|
1285
1290
|
const topology = requireClipTopology(draft, clip.entityId);
|
|
1286
1291
|
const caption = requireEntityKind(draft, otherEndpoint(topology.markerContentRelation, topology.marker.entityId), "caption");
|
|
1287
|
-
const prior = caption.payload.style;
|
|
1292
|
+
const prior = assembled.entity(caption.entityId).payload.style;
|
|
1288
1293
|
const style = isJsonObject(prior) ? prior : {};
|
|
1289
|
-
|
|
1290
|
-
...
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
style: {
|
|
1294
|
-
...style,
|
|
1295
|
-
...patch
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
});
|
|
1294
|
+
for (const updated of updateEntityFields(draft, caption.entityId, { style: {
|
|
1295
|
+
...style,
|
|
1296
|
+
...patch
|
|
1297
|
+
} })) replaceEntity(draft, updated.entityId, updated);
|
|
1299
1298
|
}
|
|
1300
1299
|
});
|
|
1301
1300
|
}
|
|
1302
1301
|
/**
|
|
1303
1302
|
* Place a Caption as a composed variant of an existing AudioScript: the
|
|
1304
|
-
* entity stores
|
|
1305
|
-
* Sequence
|
|
1303
|
+
* entity stores baseEntityIds, selection, optional style, and inherent cue-bounded
|
|
1304
|
+
* Sequence. This helper does not copy base text. The Clip and its display Marker describe this use;
|
|
1306
1305
|
* moving or stretching the returned Clip later changes the Clip/Marker,
|
|
1307
1306
|
* never the Caption entity or the AudioScript.
|
|
1308
1307
|
*/
|
|
@@ -1310,8 +1309,6 @@ var EntityTimelineEditor = class {
|
|
|
1310
1309
|
return this.transact((draft) => {
|
|
1311
1310
|
const durationMs = finitePositive(input.durationMs, "Caption durationMs");
|
|
1312
1311
|
const selections = captionSelections(input.selections);
|
|
1313
|
-
const script = requireEntityKind(draft, input.audioScriptEntityId, "audio-script");
|
|
1314
|
-
assertSelectionNamesScriptSegments(draft, script.entityId, selections);
|
|
1315
1312
|
const track = this.ensureRoleTrack(draft, input.timelineEntityId, "caption");
|
|
1316
1313
|
const content = {
|
|
1317
1314
|
entityId: this.mintEntityId(draft),
|
|
@@ -1324,12 +1321,13 @@ var EntityTimelineEditor = class {
|
|
|
1324
1321
|
},
|
|
1325
1322
|
sampling: "native",
|
|
1326
1323
|
coordinateSpace: "milliseconds",
|
|
1324
|
+
baseEntityIds: captionBaseIds(input.baseEntityIds),
|
|
1327
1325
|
selections,
|
|
1328
1326
|
...input.style === void 0 ? {} : { style: cloneJsonObject(input.style, "Caption style") }
|
|
1329
1327
|
}
|
|
1330
1328
|
};
|
|
1331
1329
|
draft.entities.push(content);
|
|
1332
|
-
|
|
1330
|
+
assembleCaptionContent(draft, content.entityId);
|
|
1333
1331
|
return this.insertPlacedClipIntoDraft(draft, {
|
|
1334
1332
|
trackEntityId: track.entityId,
|
|
1335
1333
|
contentEntityId: content.entityId,
|
|
@@ -1434,7 +1432,7 @@ var EntityTimelineEditor = class {
|
|
|
1434
1432
|
const startMs = finiteNonNegative(caption.startMs, "Caption startMs");
|
|
1435
1433
|
const durationMs = finitePositive(caption.durationMs, "Caption durationMs");
|
|
1436
1434
|
const selections = captionSelections(caption.selections);
|
|
1437
|
-
|
|
1435
|
+
const baseEntityIds = captionBaseIds(caption.baseEntityIds);
|
|
1438
1436
|
if (draft.entities.find((entity) => entity.entityId === caption.captionClipEntityId) === void 0) {
|
|
1439
1437
|
const content = {
|
|
1440
1438
|
entityId: this.mintEntityId(draft),
|
|
@@ -1447,12 +1445,14 @@ var EntityTimelineEditor = class {
|
|
|
1447
1445
|
},
|
|
1448
1446
|
sampling: "native",
|
|
1449
1447
|
coordinateSpace: "milliseconds",
|
|
1448
|
+
baseEntityIds,
|
|
1450
1449
|
selections,
|
|
1451
1450
|
...caption.style === void 0 ? {} : { style: cloneJsonObject(caption.style, "Caption style") }
|
|
1452
1451
|
}
|
|
1453
1452
|
};
|
|
1454
1453
|
draft.entities.push(content);
|
|
1455
|
-
|
|
1454
|
+
assertCaptionScript(draft, content.entityId, audioScriptEntityId);
|
|
1455
|
+
draft.relations.push(this.createRelation(draft, "caption-alignment", content.entityId, voiceEntityId, { alignment: {
|
|
1456
1456
|
start: startMs,
|
|
1457
1457
|
end: startMs + durationMs
|
|
1458
1458
|
} }));
|
|
@@ -1487,10 +1487,12 @@ var EntityTimelineEditor = class {
|
|
|
1487
1487
|
...content,
|
|
1488
1488
|
payload: {
|
|
1489
1489
|
...content.payload,
|
|
1490
|
+
baseEntityIds,
|
|
1490
1491
|
selections,
|
|
1491
1492
|
...Object.keys(style).length === 0 ? {} : { style }
|
|
1492
1493
|
}
|
|
1493
1494
|
});
|
|
1495
|
+
assertCaptionScript(draft, content.entityId, audioScriptEntityId);
|
|
1494
1496
|
this.applyClipPlacement(draft, topology.clip.entityId, {
|
|
1495
1497
|
kind: "anchored",
|
|
1496
1498
|
hostClipEntityId: voiceoverClipEntityId,
|
|
@@ -1507,7 +1509,7 @@ var EntityTimelineEditor = class {
|
|
|
1507
1509
|
}
|
|
1508
1510
|
}
|
|
1509
1511
|
});
|
|
1510
|
-
this.
|
|
1512
|
+
this.replaceCaptionAlignment(draft, content.entityId, voiceEntityId, startMs, durationMs);
|
|
1511
1513
|
}
|
|
1512
1514
|
}
|
|
1513
1515
|
ensureRoleTrackForClip(draft, clipEntityId, role) {
|
|
@@ -1516,13 +1518,13 @@ var EntityTimelineEditor = class {
|
|
|
1516
1518
|
const timeline = requireEntityKind(draft, otherEndpoint(requireOneRelation(draft, track.entityId, "timeline-track"), track.entityId), "timeline");
|
|
1517
1519
|
return this.ensureRoleTrack(draft, timeline.entityId, role);
|
|
1518
1520
|
}
|
|
1519
|
-
|
|
1520
|
-
const removed = new Set(incidentRelations(draft, captionEntityId).filter((relation) => relation.relationKind === "caption-alignment"
|
|
1521
|
+
replaceCaptionAlignment(draft, captionEntityId, voiceEntityId, startMs, durationMs) {
|
|
1522
|
+
const removed = new Set(incidentRelations(draft, captionEntityId).filter((relation) => relation.relationKind === "caption-alignment").map((relation) => relation.relationId));
|
|
1521
1523
|
draft.relations = draft.relations.filter((relation) => !removed.has(relation.relationId));
|
|
1522
1524
|
draft.relations.push(this.createRelation(draft, "caption-alignment", captionEntityId, voiceEntityId, { alignment: {
|
|
1523
1525
|
start: startMs,
|
|
1524
1526
|
end: startMs + durationMs
|
|
1525
|
-
} })
|
|
1527
|
+
} }));
|
|
1526
1528
|
}
|
|
1527
1529
|
/**
|
|
1528
1530
|
* Remove one placed Caption use. The composed AudioScript outlives the
|
|
@@ -1532,11 +1534,7 @@ var EntityTimelineEditor = class {
|
|
|
1532
1534
|
const topology = requireClipOnRole(draft, clipEntityId, "caption");
|
|
1533
1535
|
const caption = requireEntityKind(draft, otherEndpoint(topology.markerContentRelation, topology.marker.entityId), "caption");
|
|
1534
1536
|
const contentRelations = incidentRelations(draft, caption.entityId);
|
|
1535
|
-
const allowed = new Set([
|
|
1536
|
-
"caption-composition",
|
|
1537
|
-
"caption-alignment",
|
|
1538
|
-
"marker-content"
|
|
1539
|
-
]);
|
|
1537
|
+
const allowed = new Set(["caption-alignment", "marker-content"]);
|
|
1540
1538
|
const unsupported = contentRelations.filter((relation) => !allowed.has(relation.relationKind));
|
|
1541
1539
|
if (unsupported.length > 0) throw new Error(`Cannot delete Caption with unsupported Relation ${unsupported[0].relationId}`);
|
|
1542
1540
|
this.removeClipGraph(draft, clipEntityId);
|
|
@@ -2076,7 +2074,7 @@ function migrateLegacyTimelineToEntities(legacy, assetFacts, initial = {
|
|
|
2076
2074
|
const voice = contentByPartId.get(caption.speech_part_id);
|
|
2077
2075
|
const render = relations.find((relation) => relation.relationKind === "phonetic-script-render" && relation.endpoint0EntityId === voice);
|
|
2078
2076
|
const phonetic = entities.find((entity) => entity.entityId === render?.endpoint1EntityId);
|
|
2079
|
-
const script = phonetic === void 0 ? void 0 : composedAudioScript(phonetic, entities
|
|
2077
|
+
const script = phonetic === void 0 ? void 0 : composedAudioScript(phonetic, entities);
|
|
2080
2078
|
if (script === void 0) fail("Legacy Caption has no composed AudioScript");
|
|
2081
2079
|
const sourceText = scriptText(script);
|
|
2082
2080
|
const captionText = caption.text;
|
|
@@ -2097,10 +2095,10 @@ function migrateLegacyTimelineToEntities(legacy, assetFacts, initial = {
|
|
|
2097
2095
|
},
|
|
2098
2096
|
sampling: "native",
|
|
2099
2097
|
coordinateSpace: "milliseconds",
|
|
2098
|
+
baseEntityIds: [script.entityId],
|
|
2100
2099
|
selections,
|
|
2101
2100
|
...caption.style === void 0 ? {} : { style: toEntityCaptionStyle(caption.style) }
|
|
2102
2101
|
});
|
|
2103
|
-
link("caption-composition", content, script.entityId, { segmentAlignment: [] });
|
|
2104
2102
|
link("caption-alignment", content, voice, { alignment: {
|
|
2105
2103
|
start: caption.start_ms,
|
|
2106
2104
|
end: caption.start_ms + duration
|
|
@@ -2450,25 +2448,25 @@ function ensureSpeechPhoneticChain(voiceEntityId, audioScriptText, phonemeScript
|
|
|
2450
2448
|
if (renders.length === 1) {
|
|
2451
2449
|
const phonetic = entities.find((entity) => entity.entityId === renders[0].endpoint1EntityId && entity.entityKind === "phonetic-script");
|
|
2452
2450
|
if (phonetic === void 0) fail(`Voice ${voiceEntityId} has a dangling PhoneticScript render`);
|
|
2453
|
-
const script = composedAudioScript(phonetic, entities
|
|
2451
|
+
const script = composedAudioScript(phonetic, entities);
|
|
2454
2452
|
if (script === void 0 || scriptText(script) !== audioScriptText) fail(`Voice ${voiceEntityId} conflicts with the legacy Speech script`);
|
|
2455
2453
|
return phonetic.entityId;
|
|
2456
2454
|
}
|
|
2457
|
-
const
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2455
|
+
const phonetic = addEntity("phonetic-script", {
|
|
2456
|
+
baseEntityIds: [addEntity("audio-script", { segments: [{
|
|
2457
|
+
segmentId: "segment-0",
|
|
2458
|
+
text: audioScriptText
|
|
2459
|
+
}] })],
|
|
2460
|
+
...phonemeScript === void 0 ? {} : { phonemeScript }
|
|
2461
|
+
});
|
|
2463
2462
|
link("phonetic-script-render", voiceEntityId, phonetic);
|
|
2464
2463
|
return phonetic;
|
|
2465
2464
|
}
|
|
2466
|
-
function composedAudioScript(phonetic, entities
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
return entities.find((entity) => entity.entityId === otherId);
|
|
2465
|
+
function composedAudioScript(phonetic, entities) {
|
|
2466
|
+
return findComposedAudioScript({
|
|
2467
|
+
entities,
|
|
2468
|
+
relations: []
|
|
2469
|
+
}, phonetic.entityId, "phonetic-script");
|
|
2472
2470
|
}
|
|
2473
2471
|
function scriptText(script) {
|
|
2474
2472
|
const segments = script.payload.segments;
|
|
@@ -2558,6 +2556,82 @@ function fail(message) {
|
|
|
2558
2556
|
throw new EntityTimelineProjectionError(message);
|
|
2559
2557
|
}
|
|
2560
2558
|
//#endregion
|
|
2559
|
+
//#region src/entity-editor/caption-content.ts
|
|
2560
|
+
/** Author Caption content from semantic intent; callers never reconcile variant bases or assembled fields. */
|
|
2561
|
+
function prepareCaptionContent(rows, input) {
|
|
2562
|
+
const entityId = createEntityId(input.contentEntityId);
|
|
2563
|
+
const scriptId = createEntityId(input.audioScriptEntityId);
|
|
2564
|
+
if (!Number.isFinite(input.durationMs) || input.durationMs <= 0) throw new Error("Caption duration must be positive");
|
|
2565
|
+
const previous = rows.entities.find((row) => row.entityId === entityId);
|
|
2566
|
+
if (previous !== void 0 && previous.entityKind !== "caption") throw new Error("Caption content identity has a different kind");
|
|
2567
|
+
let baseEntityIds = [scriptId];
|
|
2568
|
+
if (previous !== void 0) {
|
|
2569
|
+
const source = assembleCaptionContent(rows, entityId).audioScript.entityId;
|
|
2570
|
+
const bases = variantBaseEntityIds(previous);
|
|
2571
|
+
if (source !== scriptId && !bases.includes(source)) throw new Error("Replacing an indirectly composed AudioScript requires an explicit composition change");
|
|
2572
|
+
baseEntityIds = bases.map((id) => id === source ? scriptId : id);
|
|
2573
|
+
}
|
|
2574
|
+
const candidate = {
|
|
2575
|
+
entityId,
|
|
2576
|
+
entityKind: "caption",
|
|
2577
|
+
payload: {
|
|
2578
|
+
...previous?.payload,
|
|
2579
|
+
baseEntityIds,
|
|
2580
|
+
extent: previous?.payload.extent ?? {
|
|
2581
|
+
kind: "bounded",
|
|
2582
|
+
start: 0,
|
|
2583
|
+
end: input.durationMs
|
|
2584
|
+
},
|
|
2585
|
+
sampling: previous?.payload.sampling ?? "native",
|
|
2586
|
+
coordinateSpace: previous?.payload.coordinateSpace ?? "milliseconds"
|
|
2587
|
+
}
|
|
2588
|
+
};
|
|
2589
|
+
const graph = {
|
|
2590
|
+
...rows,
|
|
2591
|
+
entities: [...rows.entities.filter((row) => row.entityId !== entityId), candidate]
|
|
2592
|
+
};
|
|
2593
|
+
const textSource = {
|
|
2594
|
+
...assembleEntityContent(graph, entityId),
|
|
2595
|
+
entityKind: "audio-script"
|
|
2596
|
+
};
|
|
2597
|
+
const selected = {
|
|
2598
|
+
...candidate,
|
|
2599
|
+
payload: {
|
|
2600
|
+
...candidate.payload,
|
|
2601
|
+
selections: structuredClone(input.selections ?? selectCaptionText(textSource, input.text))
|
|
2602
|
+
}
|
|
2603
|
+
};
|
|
2604
|
+
if (assembleCaptionContent({
|
|
2605
|
+
...graph,
|
|
2606
|
+
entities: graph.entities.map((row) => row.entityId === entityId ? selected : row)
|
|
2607
|
+
}, entityId).text !== input.text) throw new Error("Caption review text differs from its assembled variant content");
|
|
2608
|
+
return selected;
|
|
2609
|
+
}
|
|
2610
|
+
function selectCaptionText(script, text) {
|
|
2611
|
+
if (!text.trim()) throw new Error("Caption text selection must not be blank");
|
|
2612
|
+
const source = script;
|
|
2613
|
+
const fullText = assembleScriptText(source);
|
|
2614
|
+
const segments = source.payload.segments;
|
|
2615
|
+
if (text === fullText) return segments.map((segment) => ({ segmentId: segment.segmentId }));
|
|
2616
|
+
const matches = [];
|
|
2617
|
+
for (const segment of segments) {
|
|
2618
|
+
let offset = segment.text.indexOf(text);
|
|
2619
|
+
while (offset !== -1) {
|
|
2620
|
+
const start = Array.from(segment.text.slice(0, offset)).length;
|
|
2621
|
+
matches.push({
|
|
2622
|
+
segmentId: segment.segmentId,
|
|
2623
|
+
textRange: {
|
|
2624
|
+
start,
|
|
2625
|
+
end: start + Array.from(text).length
|
|
2626
|
+
}
|
|
2627
|
+
});
|
|
2628
|
+
offset = segment.text.indexOf(text, offset + 1);
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
if (matches.length !== 1) throw new Error("Caption text must select a unique AudioScript range; provide explicit selections");
|
|
2632
|
+
return matches;
|
|
2633
|
+
}
|
|
2634
|
+
//#endregion
|
|
2561
2635
|
//#region src/editor/snapshot-utils.ts
|
|
2562
2636
|
function isMap(value) {
|
|
2563
2637
|
return value instanceof Map;
|
|
@@ -4696,4 +4770,4 @@ function serverCovers(serverVV, target) {
|
|
|
4696
4770
|
return covers(server, target);
|
|
4697
4771
|
}
|
|
4698
4772
|
//#endregion
|
|
4699
|
-
export { DEFAULT_UNIT_TIME_MS, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, EntityGraphHttpClient, EntityTimelineEditor, EntityTimelineProjectionError, IMPLEMENTED_SEMANTIC_OP_KINDS, LANE_KINDS_IN_STACK_ORDER, ManualSyncDoc, MedeoHttpDocStorage, MemoryDocStorage, MengineAckFailedError, MengineDocSession, MengineHttpClient, MengineHttpRequestError, MenginePushRejectedError, MirrorVideoDocumentAdapter, PlainMemoryAdapter, SchemaValidator, ScriptCompositionError, SemanticEditor, TIMELINE_SKELETON_DURATION_MS, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, VideoDocumentValidationError, applyEntityTimelineProjection, arrangeMainTrackSeamlessly, assembleCaptionContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, projectEntityTimeline, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveSpeechOverlapByShiftingVideos, safeDurationMs, schemas_exports as schemas, selectAudioScriptSegments, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
|
4773
|
+
export { DEFAULT_UNIT_TIME_MS, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, EntityGraphHttpClient, EntityTimelineEditor, EntityTimelineProjectionError, IMPLEMENTED_SEMANTIC_OP_KINDS, LANE_KINDS_IN_STACK_ORDER, ManualSyncDoc, MedeoHttpDocStorage, MemoryDocStorage, MengineAckFailedError, MengineDocSession, MengineHttpClient, MengineHttpRequestError, MenginePushRejectedError, MirrorVideoDocumentAdapter, PlainMemoryAdapter, SchemaValidator, ScriptCompositionError, SemanticEditor, TIMELINE_SKELETON_DURATION_MS, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, VideoDocumentValidationError, applyEntityTimelineProjection, arrangeMainTrackSeamlessly, assembleCaptionContent, assembleEntityContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, prepareCaptionContent, projectEntityTimeline, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveSpeechOverlapByShiftingVideos, safeDurationMs, schemas_exports as schemas, selectAudioScriptSegments, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
package/dist/testing.d.ts
CHANGED
package/dist/testing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dt as bytesToBase64, it as VIDEO_DOCUMENT_SCHEMA_VERSION, s as createMirrorVideoDocumentAdapter, ut as base64ToBytes } from "./document-BLYcbv8E.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.3.1-alpha.
|
|
3
|
+
"version": "1.3.1-alpha.2",
|
|
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/
|
|
31
|
-
"@mengine/
|
|
32
|
-
"@mengine/
|
|
30
|
+
"@mengine/storage": "1.3.1-alpha.2",
|
|
31
|
+
"@mengine/sync": "1.3.1-alpha.2",
|
|
32
|
+
"@mengine/utils": "1.3.1-alpha.2"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "^25.9.1",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"typescript": "^6.0.3",
|
|
40
40
|
"vite-plugin-wasm": "^3.6.0",
|
|
41
41
|
"vite-plus": "^0.1.23",
|
|
42
|
-
"@mengine/
|
|
43
|
-
"@mengine/
|
|
42
|
+
"@mengine/idl-codegen": "0.0.0",
|
|
43
|
+
"@mengine/medeo-dsl": "0.0.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"loro-crdt": "^1.13.6"
|