@mengine/medeo-tool 1.4.1-alpha.1 → 1.4.1-alpha.3
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 +73 -125
- package/dist/{entity-contract-DHasvrhq.d.mts → entity-contract-DQ56Ihrh.d.mts} +42 -77
- package/dist/{script-session-AukLN7x7.mjs → entity-sandbox-BH-7F5C8.mjs} +130 -505
- package/dist/entity-sandbox-BH-7F5C8.mjs.map +1 -0
- package/dist/index.d.mts +14 -99
- package/dist/index.mjs +275 -344
- package/dist/index.mjs.map +1 -1
- package/dist/sandbox-api.d.mts +79 -295
- package/dist/worker-entry.d.mts +1 -2
- package/dist/worker-entry.mjs +190 -207
- package/dist/worker-entry.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/script-session-AukLN7x7.mjs.map +0 -1
|
@@ -1,138 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region src/document/compact-projection.ts
|
|
3
|
-
const DEFAULT_TEXT_PREVIEW_LENGTH = 24;
|
|
4
|
-
/** Kind tag shown in the first column (`video_clip` → `clip`). */
|
|
5
|
-
function kindTag(kind) {
|
|
6
|
-
return kind === "video_clip" ? "clip" : kind;
|
|
7
|
-
}
|
|
8
|
-
/** Lane label: `video_clip` tracks display as `main`, otherwise `parts_kind`. */
|
|
9
|
-
function laneLabel(partsKind) {
|
|
10
|
-
return partsKind === "video_clip" ? "main" : partsKind;
|
|
11
|
-
}
|
|
12
|
-
/** Speed token: absent → `1`; linear → numeric multiplier; anything else → `custom`. */
|
|
13
|
-
function speedToken(speedShift) {
|
|
14
|
-
if (speedShift == null) return "1";
|
|
15
|
-
if (speedShift.category === "linear") return String(speedOf(speedShift));
|
|
16
|
-
return "custom";
|
|
17
|
-
}
|
|
18
|
-
function effectiveDurationMs(part, timelineDurationMs) {
|
|
19
|
-
if (part.video_clip != null) return effectiveVideoClipDurationMs(part.video_clip);
|
|
20
|
-
if (part.speech != null) return part.speech.media_duration_ms ?? 0;
|
|
21
|
-
if (part.caption != null) return part.caption.initial_duration_ms ?? 0;
|
|
22
|
-
if (part.bgm != null) return timelineDurationMs;
|
|
23
|
-
return 0;
|
|
24
|
-
}
|
|
25
|
-
function truncateText(text, budget) {
|
|
26
|
-
if (text.length <= budget) return text;
|
|
27
|
-
return `${text.slice(0, budget)}…`;
|
|
28
|
-
}
|
|
29
|
-
function anchorToken(timePosition) {
|
|
30
|
-
if (timePosition.mode === "anchored") return `anchor=${timePosition.anchorPartId}+${timePosition.offsetMs}`;
|
|
31
|
-
if (timePosition.mode === "absolute") return "anchor=abs";
|
|
32
|
-
return "anchor=abs";
|
|
33
|
-
}
|
|
34
|
-
function clipAttrs(clip) {
|
|
35
|
-
const playIn = clip.play_in ?? 0;
|
|
36
|
-
const playOut = clip.play_out ?? 0;
|
|
37
|
-
return `media=${clip.origin_media_id ?? ""} trim=${playIn}-${playOut} speed=${speedToken(clip.speed_shift)} vol=${clip.volume ?? 0}`;
|
|
38
|
-
}
|
|
39
|
-
function partAttrs(part, item, textPreviewLength) {
|
|
40
|
-
if (part.video_clip != null) return clipAttrs(part.video_clip);
|
|
41
|
-
if (part.speech != null) return `${anchorToken(item.time_position)} dur=${part.speech.media_duration_ms ?? 0}`;
|
|
42
|
-
if (part.caption != null) {
|
|
43
|
-
const preview = truncateText(part.caption.text ?? "", textPreviewLength);
|
|
44
|
-
return `${anchorToken(item.time_position)} text="${preview}"`;
|
|
45
|
-
}
|
|
46
|
-
if (part.bgm != null) return `vol=${part.bgm.volume ?? 0}`;
|
|
47
|
-
return "";
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Render a `VideoDocument` as compact text: one header line plus one row per
|
|
51
|
-
* timeline part (optionally filtered by `onlyPartIds`). Deterministic and
|
|
52
|
-
* side-effect free — same document always yields the same string.
|
|
53
|
-
*/
|
|
54
|
-
function renderCompactProjection(document, options) {
|
|
55
|
-
const onlyPartIds = options?.onlyPartIds;
|
|
56
|
-
const textPreviewLength = options?.textPreviewLength ?? DEFAULT_TEXT_PREVIEW_LENGTH;
|
|
57
|
-
const solved = solveVideoDocument(document);
|
|
58
|
-
const library = document.part_library ?? {};
|
|
59
|
-
const tracks = document.tracks ?? [];
|
|
60
|
-
let totalParts = 0;
|
|
61
|
-
const rows = [];
|
|
62
|
-
for (const track of tracks) {
|
|
63
|
-
const partsKind = track.parts_kind;
|
|
64
|
-
if (partsKind == null) continue;
|
|
65
|
-
const lane = laneLabel(partsKind);
|
|
66
|
-
const tag = kindTag(partsKind);
|
|
67
|
-
for (const item of track.items ?? []) {
|
|
68
|
-
totalParts += 1;
|
|
69
|
-
const partId = item.part_id;
|
|
70
|
-
if (onlyPartIds != null && !onlyPartIds.has(partId)) continue;
|
|
71
|
-
const part = library[partId];
|
|
72
|
-
if (part == null) continue;
|
|
73
|
-
const abs = solved.absByPartId.get(partId) ?? 0;
|
|
74
|
-
const dur = effectiveDurationMs(part, solved.durationMs);
|
|
75
|
-
const attrs = partAttrs(part, item, textPreviewLength);
|
|
76
|
-
rows.push(`${tag} ${partId} ${lane} [${abs},${abs + dur}) ${attrs}`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return [`# draft=${document.meta.draft_id ?? ""} v=${document.meta.version ?? 0} duration=${solved.durationMs} parts=${totalParts} shown=${rows.length}`, ...rows].join("\n");
|
|
80
|
-
}
|
|
81
|
-
//#endregion
|
|
82
|
-
//#region src/sandbox/preview.ts
|
|
83
|
-
/**
|
|
84
|
-
* Collect part ids referenced by a journal for compact preview filtering.
|
|
85
|
-
* Walks known id-shaped payload keys (宁多勿少) and unions `generated_ids`.
|
|
86
|
-
*/
|
|
87
|
-
const PART_ID_KEYS = new Set([
|
|
88
|
-
"clip_id",
|
|
89
|
-
"clip_ids",
|
|
90
|
-
"before_clip_id",
|
|
91
|
-
"after_clip_id",
|
|
92
|
-
"speech_id",
|
|
93
|
-
"speech_ids",
|
|
94
|
-
"speech_part_id",
|
|
95
|
-
"caption_id",
|
|
96
|
-
"caption_ids",
|
|
97
|
-
"bgm_id",
|
|
98
|
-
"anchor_part_id",
|
|
99
|
-
"part_id",
|
|
100
|
-
"body_part_id"
|
|
101
|
-
]);
|
|
102
|
-
/** Extract every part id a journal entry touches (payload refs + minted ids). */
|
|
103
|
-
function collectAffectedPartIds(journal) {
|
|
104
|
-
const ids = /* @__PURE__ */ new Set();
|
|
105
|
-
for (const entry of journal) {
|
|
106
|
-
for (const generated of entry.generated_ids ?? []) if (generated.length > 0) ids.add(generated);
|
|
107
|
-
collectFromValue(entry.payload, ids);
|
|
108
|
-
}
|
|
109
|
-
return ids;
|
|
110
|
-
}
|
|
111
|
-
function collectFromValue(value, ids) {
|
|
112
|
-
if (value == null) return;
|
|
113
|
-
if (Array.isArray(value)) {
|
|
114
|
-
for (const item of value) collectFromValue(item, ids);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (typeof value !== "object") return;
|
|
118
|
-
for (const [key, child] of Object.entries(value)) {
|
|
119
|
-
if (PART_ID_KEYS.has(key)) {
|
|
120
|
-
if (typeof child === "string" && child.length > 0) ids.add(child);
|
|
121
|
-
else if (Array.isArray(child)) {
|
|
122
|
-
for (const item of child) if (typeof item === "string" && item.length > 0) ids.add(item);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
collectFromValue(child, ids);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Render a ChangePlan preview: header + rows for journal-affected parts only.
|
|
130
|
-
* Empty journal → empty `onlyPartIds` (header alone), matching the T2 contract.
|
|
131
|
-
*/
|
|
132
|
-
function renderPreview(document, journal) {
|
|
133
|
-
return renderCompactProjection(document, { onlyPartIds: journal.length === 0 ? /* @__PURE__ */ new Set() : collectAffectedPartIds(journal) });
|
|
134
|
-
}
|
|
135
|
-
//#endregion
|
|
1
|
+
import { applyFieldChanges, assertCanonicalEditorResources, assertFieldChanges, ensureEditorFoundation, importMediaAsset, readDocumentAudioScript } from "@mengine/medeo-client";
|
|
136
2
|
//#region ../medeo-dsl/src/entities.ts
|
|
137
3
|
function hasSequence(entity) {
|
|
138
4
|
if (isKnownNonSequenceKind(entity.entityKind) || isReservedEntityKind(entity.entityKind)) return false;
|
|
@@ -868,6 +734,8 @@ function validateVoicePayload(value, problems) {
|
|
|
868
734
|
if (voice.name !== void 0 && typeof voice.name !== "string") problems.push("voice.name must be a string when present");
|
|
869
735
|
}
|
|
870
736
|
function validateCaptionPayload(value, problems) {
|
|
737
|
+
validateExternalLocator(value, problems);
|
|
738
|
+
if (value.segmentRanges !== void 0) validateSegmentRanges(value.segmentRanges, problems);
|
|
871
739
|
const selections = value.selections;
|
|
872
740
|
if (!Array.isArray(selections)) problems.push("selections must be a non-empty array of AudioScript segment selections");
|
|
873
741
|
else {
|
|
@@ -1006,7 +874,7 @@ function isOwnedLocalEntityValuePath(entityKind, path) {
|
|
|
1006
874
|
"axvideo"
|
|
1007
875
|
].includes(entityKind) && /^(?:sampling|coordinateSpace|coordinateSpace\.unit|extent\.kind)$/.test(path)) return true;
|
|
1008
876
|
if (entityKind === "sequence-marker" && /^(?:durationPolicy|duration\.mode|timeRemapping\.(?:kind|mode))$/.test(path)) return true;
|
|
1009
|
-
if (entityKind === "sequence-marker" && /^segmentRanges\[\d+\]\.segmentId$/.test(path)) return true;
|
|
877
|
+
if ((entityKind === "sequence-marker" || entityKind === "caption") && /^segmentRanges\[\d+\]\.segmentId$/.test(path)) return true;
|
|
1010
878
|
if (entityKind === "asset" && /^(?:external\.(?:system|key)|storageKey)$/.test(path)) return true;
|
|
1011
879
|
if (isMediaAssetVariantKind(entityKind) && /^(?:external\.(?:system|key)|storageKey)$/.test(path)) return true;
|
|
1012
880
|
if (entityKind === "voice" && /^voice\.(?:system|key|name)$/.test(path)) return true;
|
|
@@ -1026,7 +894,7 @@ function isOwnedLocalIdPath(entityKind, path) {
|
|
|
1026
894
|
"phonetic-script"
|
|
1027
895
|
].includes(entityKind) && /^segments\[\d+\]\.segmentId$/.test(path)) return true;
|
|
1028
896
|
if (entityKind === "caption" && /^selections\[\d+\]\.segmentId$/.test(path)) return true;
|
|
1029
|
-
if (entityKind === "sequence-marker" && /^segmentRanges\[\d+\]\.segmentId$/.test(path)) return true;
|
|
897
|
+
if ((entityKind === "sequence-marker" || entityKind === "caption") && /^segmentRanges\[\d+\]\.segmentId$/.test(path)) return true;
|
|
1030
898
|
if (entityKind === "asset" && /^(?:tracks\[\d+\]\.trackId|renditions\[\d+\]\.renditionId)$/.test(path)) return true;
|
|
1031
899
|
return false;
|
|
1032
900
|
}
|
|
@@ -1558,12 +1426,17 @@ function businessFacades(entities, relations) {
|
|
|
1558
1426
|
create: (input) => {
|
|
1559
1427
|
if (input.entity_kind === "asset") throw new Error("Asset entities are managed by host assembly");
|
|
1560
1428
|
assertBusinessPayload(input.payload);
|
|
1429
|
+
if (input.entity_id && entities.get(input.entity_id)) throw new Error(`Entity id ${input.entity_id} already exists`);
|
|
1561
1430
|
return entities.create(input);
|
|
1562
1431
|
},
|
|
1563
1432
|
update: (input) => {
|
|
1564
1433
|
assertBusiness(input.entity_id);
|
|
1565
|
-
|
|
1566
|
-
|
|
1434
|
+
if (!Array.isArray(input.changes)) throw new Error("entities.update requires changes");
|
|
1435
|
+
for (const change of input.changes) {
|
|
1436
|
+
if (infrastructureFields.has(change.path?.[0])) throw new Error("Field is managed by host assembly");
|
|
1437
|
+
if (change.path?.[0] === "baseEntityIds" && change.op === "list.insert" && typeof change.value === "string") assertBusiness(change.value);
|
|
1438
|
+
}
|
|
1439
|
+
entities.changeFields(input);
|
|
1567
1440
|
},
|
|
1568
1441
|
declareFields: (input) => {
|
|
1569
1442
|
assertBusiness(input.entity_id);
|
|
@@ -1579,9 +1452,7 @@ function businessFacades(entities, relations) {
|
|
|
1579
1452
|
}
|
|
1580
1453
|
for (const relation of incident) relations.unlink({ relation_id: relation.relation_id });
|
|
1581
1454
|
entities.delete(input);
|
|
1582
|
-
}
|
|
1583
|
-
readCaptionContent: (input) => entities.readCaptionContent(input),
|
|
1584
|
-
readPhoneticScriptContent: (input) => entities.readPhoneticScriptContent(input)
|
|
1455
|
+
}
|
|
1585
1456
|
},
|
|
1586
1457
|
relations: {
|
|
1587
1458
|
list: () => relations.list().filter(visibleRelation),
|
|
@@ -1597,14 +1468,11 @@ function businessFacades(entities, relations) {
|
|
|
1597
1468
|
if (relation && !visibleRelation(relation)) throw new Error("Asset bindings are managed by host assembly");
|
|
1598
1469
|
relations.unlink(input);
|
|
1599
1470
|
},
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
}
|
|
1605
|
-
linkClipAnchor: (input) => relations.linkClipAnchor(input),
|
|
1606
|
-
linkPhoneticScriptRender: (input) => relations.linkPhoneticScriptRender(input),
|
|
1607
|
-
linkAudioScriptSource: (input) => relations.linkAudioScriptSource(input)
|
|
1471
|
+
update: (input) => {
|
|
1472
|
+
const relation = relations.list().find((row) => row.relation_id === input.relation_id);
|
|
1473
|
+
if (relation && !visibleRelation(relation)) throw new Error("Asset bindings are managed by host assembly");
|
|
1474
|
+
relations.update(input);
|
|
1475
|
+
}
|
|
1608
1476
|
}
|
|
1609
1477
|
};
|
|
1610
1478
|
}
|
|
@@ -1686,6 +1554,12 @@ var EntitySandbox = class {
|
|
|
1686
1554
|
case "create-entity":
|
|
1687
1555
|
lines.push(`+ entity ${command.entity.entity_id} kind=${command.entity.entity_kind}`);
|
|
1688
1556
|
break;
|
|
1557
|
+
case "change-relation":
|
|
1558
|
+
lines.push(`~ relation ${command.relation_id} ${command.changes.map((c) => c.op).join(", ")}`);
|
|
1559
|
+
break;
|
|
1560
|
+
case "change-entity":
|
|
1561
|
+
lines.push(`~ entity ${command.entity_id} ${command.changes.map((c) => c.op).join(", ")}`);
|
|
1562
|
+
break;
|
|
1689
1563
|
case "update-entity":
|
|
1690
1564
|
lines.push(`~ entity ${command.entity_id} payload`);
|
|
1691
1565
|
break;
|
|
@@ -1740,6 +1614,7 @@ var EntitySandbox = class {
|
|
|
1740
1614
|
});
|
|
1741
1615
|
},
|
|
1742
1616
|
create: (input) => this.createEntity(input),
|
|
1617
|
+
changeFields: (input) => this.changeEntity(input),
|
|
1743
1618
|
update: (input) => {
|
|
1744
1619
|
assertTrimmed(input.entity_id, "entity_id");
|
|
1745
1620
|
if (!this.state.entities.some((entity) => entity.entity_id === input.entity_id)) throw new Error(`Entity id "${input.entity_id}" does not exist`);
|
|
@@ -1753,12 +1628,28 @@ var EntitySandbox = class {
|
|
|
1753
1628
|
const current = this.state.entities.find((entity) => entity.entity_id === input.entity_id);
|
|
1754
1629
|
if (current === void 0) throw new Error(`Unknown entity "${input.entity_id}"`);
|
|
1755
1630
|
assembleEntityContent(toDslRows(this.state), createEntityId(input.entity_id));
|
|
1631
|
+
const payload = {
|
|
1632
|
+
...current.payload,
|
|
1633
|
+
...input.payload
|
|
1634
|
+
};
|
|
1635
|
+
const rows = toDslRows({
|
|
1636
|
+
...this.state,
|
|
1637
|
+
entities: this.state.entities.map((row) => row.entity_id === input.entity_id ? {
|
|
1638
|
+
...row,
|
|
1639
|
+
payload
|
|
1640
|
+
} : row)
|
|
1641
|
+
});
|
|
1642
|
+
for (const row of rows.entities) assembleEntityContent(rows, row.entityId);
|
|
1643
|
+
const assembled = assembleEntityContent(rows, createEntityId(input.entity_id));
|
|
1644
|
+
const issues = validateEntity(createEntityRef({
|
|
1645
|
+
...assembled.payload,
|
|
1646
|
+
entityId: assembled.entityId,
|
|
1647
|
+
entityKind: assembled.entityKind
|
|
1648
|
+
}));
|
|
1649
|
+
if (issues.length) throw new Error(issues.map((issue) => issue.message).join("; "));
|
|
1756
1650
|
this.replaceOwnedPayload({
|
|
1757
1651
|
entity_id: input.entity_id,
|
|
1758
|
-
payload
|
|
1759
|
-
...current.payload,
|
|
1760
|
-
...input.payload
|
|
1761
|
-
}
|
|
1652
|
+
payload
|
|
1762
1653
|
});
|
|
1763
1654
|
},
|
|
1764
1655
|
delete: (input) => this.deleteEntity(input),
|
|
@@ -1778,7 +1669,8 @@ var EntitySandbox = class {
|
|
|
1778
1669
|
linkClipAnchor: (input) => this.linkClipAnchor(input),
|
|
1779
1670
|
linkPhoneticScriptRender: (input) => this.linkPhoneticScriptRender(input),
|
|
1780
1671
|
linkAudioScriptSource: (input) => this.linkAudioScriptSource(input),
|
|
1781
|
-
unlink: (input) => this.unlinkRelation(input)
|
|
1672
|
+
unlink: (input) => this.unlinkRelation(input),
|
|
1673
|
+
update: (input) => this.changeRelation(input)
|
|
1782
1674
|
};
|
|
1783
1675
|
}
|
|
1784
1676
|
createEntity(input) {
|
|
@@ -1816,6 +1708,10 @@ var EntitySandbox = class {
|
|
|
1816
1708
|
entityId: createEntityId(entityId),
|
|
1817
1709
|
entityKind: entity.entity_kind
|
|
1818
1710
|
});
|
|
1711
|
+
assembleEntityContent(toDslRows({
|
|
1712
|
+
...this.state,
|
|
1713
|
+
entities: [...this.state.entities, entity]
|
|
1714
|
+
}), createEntityId(entityId));
|
|
1819
1715
|
this.record({
|
|
1820
1716
|
kind: "create-entity",
|
|
1821
1717
|
entity
|
|
@@ -1846,6 +1742,22 @@ var EntitySandbox = class {
|
|
|
1846
1742
|
payload
|
|
1847
1743
|
});
|
|
1848
1744
|
}
|
|
1745
|
+
changeEntity(input) {
|
|
1746
|
+
assertFieldChanges(input.changes);
|
|
1747
|
+
this.record({
|
|
1748
|
+
kind: "change-entity",
|
|
1749
|
+
entity_id: input.entity_id,
|
|
1750
|
+
changes: clone(input.changes)
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
changeRelation(input) {
|
|
1754
|
+
assertFieldChanges(input.changes);
|
|
1755
|
+
this.record({
|
|
1756
|
+
kind: "change-relation",
|
|
1757
|
+
relation_id: input.relation_id,
|
|
1758
|
+
changes: clone(input.changes)
|
|
1759
|
+
});
|
|
1760
|
+
}
|
|
1849
1761
|
deleteEntity(input) {
|
|
1850
1762
|
assertTrimmed(input.entity_id, "entity_id");
|
|
1851
1763
|
this.record({
|
|
@@ -1891,12 +1803,11 @@ var EntitySandbox = class {
|
|
|
1891
1803
|
}
|
|
1892
1804
|
}
|
|
1893
1805
|
link(input) {
|
|
1894
|
-
if (input.relation_kind === "generated") throw new Error("Author generated Relations with relations.linkGenerated({ output_entity_id, input_entity_id })");
|
|
1895
1806
|
const spec = builtInRelationSpecs.find((candidate) => candidate.kind === input.relation_kind);
|
|
1896
1807
|
if (spec == null) throw new Error(`Unknown Relation kind "${String(input.relation_kind)}"`);
|
|
1897
1808
|
const relation = this.relationFromInput(input, input.relation_kind);
|
|
1898
1809
|
const [first, second] = this.refsFor(relation);
|
|
1899
|
-
new BiRelationIndex().
|
|
1810
|
+
new BiRelationIndex().linkRuntime({
|
|
1900
1811
|
relationId: createRelationId(relation.relation_id),
|
|
1901
1812
|
spec,
|
|
1902
1813
|
endpoints: [first, second],
|
|
@@ -2037,7 +1948,7 @@ var EntitySandbox = class {
|
|
|
2037
1948
|
if (command.entity.entity_kind === "audio-script" && this.state.entities.some((entity) => entity.entity_kind === "audio-script")) throw new Error("The project AudioScript already exists; edit its segments instead");
|
|
2038
1949
|
if (enforceIdentity && this.state.entities.some((entity) => entity.entity_id === command.entity.entity_id)) throw new Error(`Entity id "${command.entity.entity_id}" already exists`);
|
|
2039
1950
|
const original = this.original.entities.find((entity) => entity.entity_id === command.entity.entity_id);
|
|
2040
|
-
if (enforceIdentity && original != null
|
|
1951
|
+
if (enforceIdentity && original != null) throw new Error(`Entity id "${command.entity.entity_id}" was originally kind "${original.entity_kind}" and cannot be recreated as "${command.entity.entity_kind}"`);
|
|
2041
1952
|
this.state.entities.push(clone(command.entity));
|
|
2042
1953
|
if (command.entity.entity_kind === "audio-script" && this.state.audioScriptEntityId === null) this.state.audioScriptEntityId = command.entity.entity_id;
|
|
2043
1954
|
return;
|
|
@@ -2053,8 +1964,66 @@ var EntitySandbox = class {
|
|
|
2053
1964
|
};
|
|
2054
1965
|
return;
|
|
2055
1966
|
}
|
|
1967
|
+
case "change-entity": {
|
|
1968
|
+
const original = this.state;
|
|
1969
|
+
this.state = cloneSnapshot(original);
|
|
1970
|
+
try {
|
|
1971
|
+
const touched = new Set([command.entity_id]);
|
|
1972
|
+
for (const change of command.changes) {
|
|
1973
|
+
if (change.path[0] === "baseEntityIds" && change.op === "list.move") throw new Error("Composition bases are unordered; list.move is not applicable");
|
|
1974
|
+
const owner = resolveEntityFieldOwner(toDslRows(this.state), createEntityId(command.entity_id), change.path[0]);
|
|
1975
|
+
const row = this.state.entities.find((row) => row.entity_id === owner);
|
|
1976
|
+
row.payload = applyFieldChanges(row.payload, [change]);
|
|
1977
|
+
touched.add(owner);
|
|
1978
|
+
}
|
|
1979
|
+
const rows = toDslRows(this.state);
|
|
1980
|
+
for (const row of rows.entities) {
|
|
1981
|
+
const assembled = assembleEntityContent(rows, row.entityId);
|
|
1982
|
+
if (touched.has(row.entityId)) {
|
|
1983
|
+
const issues = validateEntity(createEntityRef({
|
|
1984
|
+
...assembled.payload,
|
|
1985
|
+
entityId: row.entityId,
|
|
1986
|
+
entityKind: row.entityKind
|
|
1987
|
+
}));
|
|
1988
|
+
if (issues.length) throw new Error(issues.map((issue) => issue.message).join("; "));
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
} catch (error) {
|
|
1992
|
+
this.state = original;
|
|
1993
|
+
throw error;
|
|
1994
|
+
}
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
case "change-relation": {
|
|
1998
|
+
const index = this.state.relations.findIndex((row) => row.relation_id === command.relation_id);
|
|
1999
|
+
if (index < 0) throw new Error(`Unknown relation ${command.relation_id}`);
|
|
2000
|
+
for (const change of command.changes) if (!["metadata", "trace"].includes(change.path[0]) || change.path.length < 2) throw new Error("Relation changes may only edit metadata or trace fields");
|
|
2001
|
+
const current = this.state.relations[index];
|
|
2002
|
+
const fields = applyFieldChanges({
|
|
2003
|
+
metadata: current.metadata,
|
|
2004
|
+
trace: current.trace
|
|
2005
|
+
}, command.changes);
|
|
2006
|
+
const next = {
|
|
2007
|
+
...current,
|
|
2008
|
+
metadata: fields.metadata,
|
|
2009
|
+
trace: fields.trace
|
|
2010
|
+
};
|
|
2011
|
+
const spec = builtInRelationSpecs.find((spec) => spec.kind === next.relation_kind);
|
|
2012
|
+
new BiRelationIndex().linkRuntime({
|
|
2013
|
+
relationId: createRelationId(next.relation_id),
|
|
2014
|
+
spec,
|
|
2015
|
+
endpoints: this.refsFor(next),
|
|
2016
|
+
metadata: next.metadata,
|
|
2017
|
+
trace: next.trace
|
|
2018
|
+
});
|
|
2019
|
+
this.state.relations[index] = next;
|
|
2020
|
+
return;
|
|
2021
|
+
}
|
|
2056
2022
|
case "delete-entity": {
|
|
2057
|
-
|
|
2023
|
+
const target = this.state.entities.find((entity) => entity.entity_id === command.entity_id);
|
|
2024
|
+
if (target && ["audio-script", "timeline"].includes(target.entity_kind)) throw new Error("The document AudioScript is a fixed project identity and cannot be deleted");
|
|
2025
|
+
const dependents = this.state.entities.filter((entity) => Array.isArray(entity.payload.baseEntityIds) && entity.payload.baseEntityIds.includes(command.entity_id));
|
|
2026
|
+
if (dependents.length) throw new Error(`Entity ${command.entity_id} is still referenced by variants: ${dependents.map((row) => row.entity_id).join(", ")}`);
|
|
2058
2027
|
const index = this.state.entities.findIndex((entity) => entity.entity_id === command.entity_id);
|
|
2059
2028
|
if (index < 0) throw new Error(`Entity id "${command.entity_id}" does not exist`);
|
|
2060
2029
|
const incidentRelationIds = this.state.relations.filter((relation) => relation.endpoint_0_entity_id === command.entity_id || relation.endpoint_1_entity_id === command.entity_id).map((relation) => relation.relation_id).sort();
|
|
@@ -2128,350 +2097,6 @@ const numericMarkerComparators = { compareMarkerPoints: (_marker, _range, left,
|
|
|
2128
2097
|
return left - right;
|
|
2129
2098
|
} };
|
|
2130
2099
|
//#endregion
|
|
2131
|
-
|
|
2132
|
-
const LOG_LINE_MAX = 2e3;
|
|
2133
|
-
const LOG_LINE_CAP = 1e3;
|
|
2134
|
-
const LOG_BYTE_CAP = 64 * 1024;
|
|
2135
|
-
const TRUNCATE_MARK = "[truncated]";
|
|
2136
|
-
const LOG_TRUNCATED = "[log truncated]";
|
|
2137
|
-
const ENTITY_CHECKPOINT_INDEX = Symbol("entityCheckpointIndex");
|
|
2138
|
-
/** Session core for one forked document; globals stay identity-stable across rollback. */
|
|
2139
|
-
var EditSandboxSession = class {
|
|
2140
|
-
original;
|
|
2141
|
-
idFactory;
|
|
2142
|
-
onEntry;
|
|
2143
|
-
onLog;
|
|
2144
|
-
onTruncate;
|
|
2145
|
-
entitySandbox;
|
|
2146
|
-
current;
|
|
2147
|
-
/** Adapter journal length already accounted for — new slices are real commits. */
|
|
2148
|
-
adapterJournalSeen = 0;
|
|
2149
|
-
entries = [];
|
|
2150
|
-
logs = [];
|
|
2151
|
-
logBytes = 0;
|
|
2152
|
-
logCapped = false;
|
|
2153
|
-
edit;
|
|
2154
|
-
timeline;
|
|
2155
|
-
entities;
|
|
2156
|
-
relations;
|
|
2157
|
-
console;
|
|
2158
|
-
checkpoint;
|
|
2159
|
-
rollbackTo;
|
|
2160
|
-
constructor(document, options) {
|
|
2161
|
-
this.original = structuredClone(document);
|
|
2162
|
-
this.idFactory = options?.idFactory;
|
|
2163
|
-
this.onEntry = options?.onEntry;
|
|
2164
|
-
this.onLog = options?.onLog;
|
|
2165
|
-
this.onTruncate = options?.onTruncate;
|
|
2166
|
-
this.entitySandbox = new EntitySandbox({
|
|
2167
|
-
state: options?.entityState,
|
|
2168
|
-
idFactory: options?.domainIdFactory ?? (() => {
|
|
2169
|
-
throw new Error("Entity id factory is unavailable in this sandbox host");
|
|
2170
|
-
}),
|
|
2171
|
-
onCommand: options?.onEntityCommand,
|
|
2172
|
-
onTruncate: options?.onEntityTruncate
|
|
2173
|
-
});
|
|
2174
|
-
this.current = this.boot(structuredClone(this.original));
|
|
2175
|
-
this.adapterJournalSeen = this.current.adapter.journal.length;
|
|
2176
|
-
this.edit = this.buildEditFacade();
|
|
2177
|
-
this.timeline = this.buildTimelineFacade();
|
|
2178
|
-
this.entities = this.entitySandbox.entities;
|
|
2179
|
-
this.relations = this.entitySandbox.relations;
|
|
2180
|
-
this.console = this.buildConsoleShim();
|
|
2181
|
-
this.checkpoint = () => {
|
|
2182
|
-
const checkpoint = { index: this.entries.length };
|
|
2183
|
-
Object.defineProperty(checkpoint, ENTITY_CHECKPOINT_INDEX, {
|
|
2184
|
-
value: this.entitySandbox.commandCount,
|
|
2185
|
-
enumerable: false
|
|
2186
|
-
});
|
|
2187
|
-
return checkpoint;
|
|
2188
|
-
};
|
|
2189
|
-
this.rollbackTo = (cp) => this.doRollbackTo(cp);
|
|
2190
|
-
}
|
|
2191
|
-
/** Assemble a ChangePlan from the self-maintained journal + current preview. */
|
|
2192
|
-
buildPlan(baseVersion) {
|
|
2193
|
-
const entityCommands = this.entitySandbox.getCommands();
|
|
2194
|
-
if (this.entries.length > 0 && entityCommands.length > 0) throw new Error("A sandbox plan cannot mix timeline and entity mutations; run and commit them as separate plans");
|
|
2195
|
-
const entityPlan = this.entitySandbox.buildPlan();
|
|
2196
|
-
const planKind = entityCommands.length > 0 ? "entities" : "timeline";
|
|
2197
|
-
return {
|
|
2198
|
-
plan_kind: planKind,
|
|
2199
|
-
doc_id: this.original.meta.draft_id ?? "",
|
|
2200
|
-
base_version: baseVersion,
|
|
2201
|
-
ops: this.entries.slice(),
|
|
2202
|
-
entity_base_revision: entityPlan.base_revision,
|
|
2203
|
-
entity_commands: entityPlan.commands,
|
|
2204
|
-
...planKind === "entities" ? { entity_rows: entityPlan.rows } : {},
|
|
2205
|
-
...planKind === "entities" ? {
|
|
2206
|
-
deleted_entity_ids: entityPlan.deleted_entity_ids,
|
|
2207
|
-
deleted_relation_ids: entityPlan.deleted_relation_ids
|
|
2208
|
-
} : {},
|
|
2209
|
-
preview: planKind === "entities" ? this.entitySandbox.renderPreview() : renderPreview(this.current.adapter.snapshot(), this.entries),
|
|
2210
|
-
logs: this.logs.slice()
|
|
2211
|
-
};
|
|
2212
|
-
}
|
|
2213
|
-
getEntries() {
|
|
2214
|
-
return this.entries;
|
|
2215
|
-
}
|
|
2216
|
-
getLogs() {
|
|
2217
|
-
return this.logs;
|
|
2218
|
-
}
|
|
2219
|
-
boot(document) {
|
|
2220
|
-
const sandbox = createEditSandbox(document, this.idFactory != null ? { idFactory: this.idFactory } : void 0);
|
|
2221
|
-
return {
|
|
2222
|
-
adapter: sandbox.adapter,
|
|
2223
|
-
editor: sandbox.editor
|
|
2224
|
-
};
|
|
2225
|
-
}
|
|
2226
|
-
doRollbackTo(cp) {
|
|
2227
|
-
if (cp.index > this.entries.length) throw new Error(`rollbackTo: checkpoint index ${cp.index} is past journal length ${this.entries.length}`);
|
|
2228
|
-
const prefix = this.entries.slice(0, cp.index);
|
|
2229
|
-
const next = this.boot(structuredClone(this.original));
|
|
2230
|
-
replayJournalSync(next.adapter, prefix);
|
|
2231
|
-
this.entries.length = 0;
|
|
2232
|
-
this.entries.push(...prefix);
|
|
2233
|
-
this.current = next;
|
|
2234
|
-
this.adapterJournalSeen = next.adapter.journal.length;
|
|
2235
|
-
this.onTruncate?.(prefix.length);
|
|
2236
|
-
const entityIndex = cp[ENTITY_CHECKPOINT_INDEX];
|
|
2237
|
-
if (entityIndex !== void 0) this.entitySandbox.rollbackTo(entityIndex);
|
|
2238
|
-
}
|
|
2239
|
-
captureNewEntries() {
|
|
2240
|
-
const journal = this.current.adapter.journal;
|
|
2241
|
-
if (journal.length <= this.adapterJournalSeen) return;
|
|
2242
|
-
const fresh = journal.slice(this.adapterJournalSeen);
|
|
2243
|
-
this.adapterJournalSeen = journal.length;
|
|
2244
|
-
for (const entry of fresh) {
|
|
2245
|
-
this.entries.push(entry);
|
|
2246
|
-
this.onEntry?.(entry);
|
|
2247
|
-
}
|
|
2248
|
-
}
|
|
2249
|
-
appendLog(line) {
|
|
2250
|
-
if (this.logCapped) return;
|
|
2251
|
-
if (this.logs.length >= LOG_LINE_CAP || this.logBytes >= LOG_BYTE_CAP) {
|
|
2252
|
-
this.logs.push(LOG_TRUNCATED);
|
|
2253
|
-
this.logCapped = true;
|
|
2254
|
-
this.onLog?.(LOG_TRUNCATED);
|
|
2255
|
-
return;
|
|
2256
|
-
}
|
|
2257
|
-
let out = line;
|
|
2258
|
-
if (out.length > LOG_LINE_MAX) out = `${out.slice(0, LOG_LINE_MAX - 11)}${TRUNCATE_MARK}`;
|
|
2259
|
-
this.logs.push(out);
|
|
2260
|
-
this.logBytes += out.length;
|
|
2261
|
-
this.onLog?.(out);
|
|
2262
|
-
}
|
|
2263
|
-
buildConsoleShim() {
|
|
2264
|
-
const write = (...args) => {
|
|
2265
|
-
this.appendLog(args.map(formatLogArg).join(" "));
|
|
2266
|
-
};
|
|
2267
|
-
return {
|
|
2268
|
-
log: write,
|
|
2269
|
-
info: write,
|
|
2270
|
-
warn: write,
|
|
2271
|
-
error: write
|
|
2272
|
-
};
|
|
2273
|
-
}
|
|
2274
|
-
buildEditFacade() {
|
|
2275
|
-
const wrap = (method) => async (input) => {
|
|
2276
|
-
await method(this.current.editor, input);
|
|
2277
|
-
this.captureNewEntries();
|
|
2278
|
-
};
|
|
2279
|
-
return {
|
|
2280
|
-
addSpeeches: wrap((e, i) => e.addSpeeches(i)),
|
|
2281
|
-
addVideoClips: async (input) => {
|
|
2282
|
-
const needsAppend = input.before_clip_id == null && input.after_clip_id == null && input.clips.some((clip) => clip.start_ms == null);
|
|
2283
|
-
const appendAt = this.timeline.snapshot().timeline?.duration_ms ?? 0;
|
|
2284
|
-
const normalized = needsAppend ? {
|
|
2285
|
-
...input,
|
|
2286
|
-
clips: input.clips.map((clip) => clip.start_ms == null ? {
|
|
2287
|
-
...clip,
|
|
2288
|
-
start_ms: appendAt
|
|
2289
|
-
} : clip)
|
|
2290
|
-
} : input;
|
|
2291
|
-
await this.current.editor.addVideoClips(normalized);
|
|
2292
|
-
this.captureNewEntries();
|
|
2293
|
-
},
|
|
2294
|
-
adjustBgmVolume: wrap((e, i) => e.adjustBgmVolume(i)),
|
|
2295
|
-
adjustSpeechVolume: wrap((e, i) => e.adjustSpeechVolume(i)),
|
|
2296
|
-
adjustVideoClipDuration: wrap((e, i) => e.adjustVideoClipDuration(i)),
|
|
2297
|
-
adjustVideoClipVolume: wrap((e, i) => e.adjustVideoClipVolume(i)),
|
|
2298
|
-
changeSpeechScript: wrap((e, i) => e.changeSpeechScript(i)),
|
|
2299
|
-
changeSpeechVoice: wrap((e, i) => e.changeSpeechVoice(i)),
|
|
2300
|
-
deleteBgm: wrap((e, i) => e.deleteBgm(i)),
|
|
2301
|
-
deleteSpeeches: wrap((e, i) => e.deleteSpeeches(i)),
|
|
2302
|
-
deleteVideoClips: wrap((e, i) => e.deleteVideoClips(i)),
|
|
2303
|
-
moveSpeeches: wrap((e, i) => e.moveSpeeches(i)),
|
|
2304
|
-
moveVideoClips: wrap((e, i) => e.moveVideoClips(i)),
|
|
2305
|
-
moveVideoClipsByAnchor: wrap((e, i) => e.moveVideoClipsByAnchor(i)),
|
|
2306
|
-
replaceVideoClipContent: wrap((e, i) => e.replaceVideoClipContent(i)),
|
|
2307
|
-
replaceVideoClipSequence: wrap((e, i) => e.replaceVideoClipSequence(i)),
|
|
2308
|
-
setBgm: wrap((e, i) => e.setBgm(i)),
|
|
2309
|
-
setCaptionStyle: wrap((e, i) => e.setCaptionStyle(i)),
|
|
2310
|
-
setCaptionVisibility: wrap((e, i) => e.setCaptionVisibility(i)),
|
|
2311
|
-
setVideoClipSpeedShift: wrap((e, i) => e.setVideoClipSpeedShift(i))
|
|
2312
|
-
};
|
|
2313
|
-
}
|
|
2314
|
-
buildTimelineFacade() {
|
|
2315
|
-
return {
|
|
2316
|
-
snapshot: () => fromVideoDocument(this.current.adapter.snapshot()),
|
|
2317
|
-
clipsInRange: (startMs, endMs) => this.clipsInRange(startMs, endMs),
|
|
2318
|
-
part: (id) => this.part(id)
|
|
2319
|
-
};
|
|
2320
|
-
}
|
|
2321
|
-
clipsInRange(startMs, endMs) {
|
|
2322
|
-
const document = this.current.adapter.snapshot();
|
|
2323
|
-
const solved = solveVideoDocument(document);
|
|
2324
|
-
const library = document.part_library ?? {};
|
|
2325
|
-
const main = document.tracks?.find((track) => track.parts_kind === "video_clip");
|
|
2326
|
-
const out = [];
|
|
2327
|
-
for (const item of main?.items ?? []) {
|
|
2328
|
-
const id = item.part_id;
|
|
2329
|
-
if (id == null) continue;
|
|
2330
|
-
const clip = library[id]?.video_clip;
|
|
2331
|
-
if (clip == null) continue;
|
|
2332
|
-
const start = solved.absByPartId.get(id) ?? 0;
|
|
2333
|
-
const duration = effectiveVideoClipDurationMs(clip);
|
|
2334
|
-
const end = start + duration;
|
|
2335
|
-
const mid = start + duration / 2;
|
|
2336
|
-
if (!(mid >= startMs && mid < endMs)) continue;
|
|
2337
|
-
out.push({
|
|
2338
|
-
id,
|
|
2339
|
-
start_ms: start,
|
|
2340
|
-
end_ms: end,
|
|
2341
|
-
duration_ms: duration,
|
|
2342
|
-
speed_shift: clip.speed_shift,
|
|
2343
|
-
volume: clip.volume,
|
|
2344
|
-
media_id: clip.origin_media_id
|
|
2345
|
-
});
|
|
2346
|
-
}
|
|
2347
|
-
return out;
|
|
2348
|
-
}
|
|
2349
|
-
part(id) {
|
|
2350
|
-
const document = this.current.adapter.snapshot();
|
|
2351
|
-
const part = (document.part_library ?? {})[id];
|
|
2352
|
-
if (part == null) return null;
|
|
2353
|
-
let lane = "main";
|
|
2354
|
-
let kind = "video_clip";
|
|
2355
|
-
for (const track of document.tracks ?? []) {
|
|
2356
|
-
if (!(track.items ?? []).some((item) => item.part_id === id)) continue;
|
|
2357
|
-
const partsKind = track.parts_kind ?? "video_clip";
|
|
2358
|
-
kind = partsKind;
|
|
2359
|
-
lane = partsKind === "video_clip" ? "main" : partsKind;
|
|
2360
|
-
break;
|
|
2361
|
-
}
|
|
2362
|
-
const solved = solveVideoDocument(document);
|
|
2363
|
-
const start = solved.absByPartId.get(id) ?? 0;
|
|
2364
|
-
let duration = 0;
|
|
2365
|
-
if (part.video_clip != null) duration = effectiveVideoClipDurationMs(part.video_clip);
|
|
2366
|
-
else if (part.speech != null) duration = part.speech.media_duration_ms ?? 0;
|
|
2367
|
-
else if (part.caption != null) duration = part.caption.initial_duration_ms ?? 0;
|
|
2368
|
-
else if (part.bgm != null) duration = solved.durationMs;
|
|
2369
|
-
return {
|
|
2370
|
-
id,
|
|
2371
|
-
kind,
|
|
2372
|
-
lane,
|
|
2373
|
-
start_ms: start,
|
|
2374
|
-
end_ms: start + duration,
|
|
2375
|
-
duration_ms: duration,
|
|
2376
|
-
part
|
|
2377
|
-
};
|
|
2378
|
-
}
|
|
2379
|
-
};
|
|
2380
|
-
function formatLogArg(value) {
|
|
2381
|
-
if (typeof value === "string") return value;
|
|
2382
|
-
if (typeof value === "number" || typeof value === "boolean" || value === null || value === void 0) return String(value);
|
|
2383
|
-
try {
|
|
2384
|
-
return JSON.stringify(value);
|
|
2385
|
-
} catch {
|
|
2386
|
-
return "[unstringifiable]";
|
|
2387
|
-
}
|
|
2388
|
-
}
|
|
2389
|
-
/**
|
|
2390
|
-
* Synchronous journal replay for rollback. Editor methods are `async` only for
|
|
2391
|
-
* interface uniformity — their bodies complete before the Promise is returned,
|
|
2392
|
-
* so voiding the call applies mutations in-order without yielding.
|
|
2393
|
-
*/
|
|
2394
|
-
function replayJournalSync(adapter, journal) {
|
|
2395
|
-
const queue = [];
|
|
2396
|
-
const idFactory = (_prefix) => {
|
|
2397
|
-
const id = queue.shift();
|
|
2398
|
-
if (id == null) throw new Error("unrecorded id");
|
|
2399
|
-
return id;
|
|
2400
|
-
};
|
|
2401
|
-
const editor = new SemanticEditor(adapter, new SchemaValidator(), idFactory);
|
|
2402
|
-
for (const entry of journal) {
|
|
2403
|
-
queue.push(...entry.generated_ids ?? []);
|
|
2404
|
-
const payload = entry.payload;
|
|
2405
|
-
switch (entry.kind) {
|
|
2406
|
-
case "MoveVideoClips":
|
|
2407
|
-
editor.moveVideoClips(payload);
|
|
2408
|
-
break;
|
|
2409
|
-
case "MoveVideoClipsByAnchor":
|
|
2410
|
-
editor.moveVideoClipsByAnchor(payload);
|
|
2411
|
-
break;
|
|
2412
|
-
case "DeleteVideoClips":
|
|
2413
|
-
editor.deleteVideoClips(payload);
|
|
2414
|
-
break;
|
|
2415
|
-
case "AddVideoClips":
|
|
2416
|
-
editor.addVideoClips(payload);
|
|
2417
|
-
break;
|
|
2418
|
-
case "AdjustVideoClipVolume":
|
|
2419
|
-
editor.adjustVideoClipVolume(payload);
|
|
2420
|
-
break;
|
|
2421
|
-
case "SetVideoClipSpeedShift":
|
|
2422
|
-
editor.setVideoClipSpeedShift(payload);
|
|
2423
|
-
break;
|
|
2424
|
-
case "ReplaceVideoClipContent":
|
|
2425
|
-
editor.replaceVideoClipContent(payload);
|
|
2426
|
-
break;
|
|
2427
|
-
case "ReplaceVideoClipSequence":
|
|
2428
|
-
editor.replaceVideoClipSequence(payload);
|
|
2429
|
-
break;
|
|
2430
|
-
case "AdjustVideoClipDuration":
|
|
2431
|
-
editor.adjustVideoClipDuration(payload);
|
|
2432
|
-
break;
|
|
2433
|
-
case "AddSpeeches":
|
|
2434
|
-
editor.addSpeeches(payload);
|
|
2435
|
-
break;
|
|
2436
|
-
case "DeleteSpeeches":
|
|
2437
|
-
editor.deleteSpeeches(payload);
|
|
2438
|
-
break;
|
|
2439
|
-
case "MoveSpeeches":
|
|
2440
|
-
editor.moveSpeeches(payload);
|
|
2441
|
-
break;
|
|
2442
|
-
case "ChangeSpeechScript":
|
|
2443
|
-
editor.changeSpeechScript(payload);
|
|
2444
|
-
break;
|
|
2445
|
-
case "ChangeSpeechVoice":
|
|
2446
|
-
editor.changeSpeechVoice(payload);
|
|
2447
|
-
break;
|
|
2448
|
-
case "AdjustSpeechVolume":
|
|
2449
|
-
editor.adjustSpeechVolume(payload);
|
|
2450
|
-
break;
|
|
2451
|
-
case "SetCaptionVisibility":
|
|
2452
|
-
editor.setCaptionVisibility(payload);
|
|
2453
|
-
break;
|
|
2454
|
-
case "SetCaptionStyle":
|
|
2455
|
-
editor.setCaptionStyle(payload);
|
|
2456
|
-
break;
|
|
2457
|
-
case "SetBgm":
|
|
2458
|
-
editor.setBgm(payload);
|
|
2459
|
-
break;
|
|
2460
|
-
case "DeleteBgm":
|
|
2461
|
-
editor.deleteBgm(payload);
|
|
2462
|
-
break;
|
|
2463
|
-
case "AdjustBgmVolume":
|
|
2464
|
-
editor.adjustBgmVolume(payload);
|
|
2465
|
-
break;
|
|
2466
|
-
default: {
|
|
2467
|
-
const _exhaustive = entry.kind;
|
|
2468
|
-
throw new Error(`replayJournalSync: unsupported kind ${String(_exhaustive)}`);
|
|
2469
|
-
}
|
|
2470
|
-
}
|
|
2471
|
-
if (queue.length > 0) throw new Error("unconsumed ids");
|
|
2472
|
-
}
|
|
2473
|
-
}
|
|
2474
|
-
//#endregion
|
|
2475
|
-
export { createEntityId as a, collectAffectedPartIds as c, businessState as i, renderPreview as l, EntitySandbox as n, createRelationId as o, businessFacades as r, isMediaAssetVariantKind as s, EditSandboxSession as t, renderCompactProjection as u };
|
|
2100
|
+
export { createEntityId as a, businessState as i, toDslRows as n, createRelationId as o, businessFacades as r, isMediaAssetVariantKind as s, EntitySandbox as t };
|
|
2476
2101
|
|
|
2477
|
-
//# sourceMappingURL=
|
|
2102
|
+
//# sourceMappingURL=entity-sandbox-BH-7F5C8.mjs.map
|