@mengine/medeo-tool 1.4.1-alpha.2 → 1.4.1-alpha.4
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 +67 -141
- package/dist/{entity-contract-Cpf3P69H.d.mts → entity-contract-DQ56Ihrh.d.mts} +36 -76
- package/dist/{script-session-lXpqmupK.mjs → entity-sandbox-OArq9NSH.mjs} +131 -509
- package/dist/entity-sandbox-OArq9NSH.mjs.map +1 -0
- package/dist/index.d.mts +3 -99
- package/dist/index.mjs +252 -372
- package/dist/index.mjs.map +1 -1
- package/dist/sandbox-api.d.mts +59 -293
- package/dist/worker-entry.d.mts +1 -2
- package/dist/worker-entry.mjs +77 -214
- package/dist/worker-entry.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/script-session-lXpqmupK.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;
|
|
@@ -1560,12 +1426,17 @@ function businessFacades(entities, relations) {
|
|
|
1560
1426
|
create: (input) => {
|
|
1561
1427
|
if (input.entity_kind === "asset") throw new Error("Asset entities are managed by host assembly");
|
|
1562
1428
|
assertBusinessPayload(input.payload);
|
|
1429
|
+
if (input.entity_id && entities.get(input.entity_id)) throw new Error(`Entity id ${input.entity_id} already exists`);
|
|
1563
1430
|
return entities.create(input);
|
|
1564
1431
|
},
|
|
1565
1432
|
update: (input) => {
|
|
1566
1433
|
assertBusiness(input.entity_id);
|
|
1567
|
-
|
|
1568
|
-
|
|
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);
|
|
1569
1440
|
},
|
|
1570
1441
|
declareFields: (input) => {
|
|
1571
1442
|
assertBusiness(input.entity_id);
|
|
@@ -1581,9 +1452,7 @@ function businessFacades(entities, relations) {
|
|
|
1581
1452
|
}
|
|
1582
1453
|
for (const relation of incident) relations.unlink({ relation_id: relation.relation_id });
|
|
1583
1454
|
entities.delete(input);
|
|
1584
|
-
}
|
|
1585
|
-
readCaptionContent: (input) => entities.readCaptionContent(input),
|
|
1586
|
-
readPhoneticScriptContent: (input) => entities.readPhoneticScriptContent(input)
|
|
1455
|
+
}
|
|
1587
1456
|
},
|
|
1588
1457
|
relations: {
|
|
1589
1458
|
list: () => relations.list().filter(visibleRelation),
|
|
@@ -1599,14 +1468,11 @@ function businessFacades(entities, relations) {
|
|
|
1599
1468
|
if (relation && !visibleRelation(relation)) throw new Error("Asset bindings are managed by host assembly");
|
|
1600
1469
|
relations.unlink(input);
|
|
1601
1470
|
},
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
}
|
|
1607
|
-
linkClipAnchor: (input) => relations.linkClipAnchor(input),
|
|
1608
|
-
linkPhoneticScriptRender: (input) => relations.linkPhoneticScriptRender(input),
|
|
1609
|
-
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
|
+
}
|
|
1610
1476
|
}
|
|
1611
1477
|
};
|
|
1612
1478
|
}
|
|
@@ -1646,10 +1512,14 @@ var EntitySandbox = class {
|
|
|
1646
1512
|
}
|
|
1647
1513
|
/** Host-owned fixed structure is journaled through the same CAS graph as model edits. */
|
|
1648
1514
|
ensureFoundation(timelinePayload = {}) {
|
|
1649
|
-
const foundation = ensureEditorFoundation(toDslRows(this.state), this.idFactory, timelinePayload);
|
|
1515
|
+
const foundation = ensureEditorFoundation(toDslRows(this.state), this.idFactory, timelinePayload, this.state.audioScriptEntityId);
|
|
1650
1516
|
this.appendResourceRows(foundation.rows);
|
|
1651
1517
|
if (this.state.audioScriptEntityId === null) this.state.audioScriptEntityId = foundation.audioScriptEntityId;
|
|
1652
1518
|
}
|
|
1519
|
+
/** Host assembly resolves the text owner before a resource Caption is complete. */
|
|
1520
|
+
captionAudioScriptId(entityId) {
|
|
1521
|
+
return findComposedAudioScript(toDslRows(this.state), createEntityId(entityId), "caption").entityId;
|
|
1522
|
+
}
|
|
1653
1523
|
get audioScriptEntityId() {
|
|
1654
1524
|
return this.state.audioScriptEntityId;
|
|
1655
1525
|
}
|
|
@@ -1688,6 +1558,12 @@ var EntitySandbox = class {
|
|
|
1688
1558
|
case "create-entity":
|
|
1689
1559
|
lines.push(`+ entity ${command.entity.entity_id} kind=${command.entity.entity_kind}`);
|
|
1690
1560
|
break;
|
|
1561
|
+
case "change-relation":
|
|
1562
|
+
lines.push(`~ relation ${command.relation_id} ${command.changes.map((c) => c.op).join(", ")}`);
|
|
1563
|
+
break;
|
|
1564
|
+
case "change-entity":
|
|
1565
|
+
lines.push(`~ entity ${command.entity_id} ${command.changes.map((c) => c.op).join(", ")}`);
|
|
1566
|
+
break;
|
|
1691
1567
|
case "update-entity":
|
|
1692
1568
|
lines.push(`~ entity ${command.entity_id} payload`);
|
|
1693
1569
|
break;
|
|
@@ -1742,6 +1618,7 @@ var EntitySandbox = class {
|
|
|
1742
1618
|
});
|
|
1743
1619
|
},
|
|
1744
1620
|
create: (input) => this.createEntity(input),
|
|
1621
|
+
changeFields: (input) => this.changeEntity(input),
|
|
1745
1622
|
update: (input) => {
|
|
1746
1623
|
assertTrimmed(input.entity_id, "entity_id");
|
|
1747
1624
|
if (!this.state.entities.some((entity) => entity.entity_id === input.entity_id)) throw new Error(`Entity id "${input.entity_id}" does not exist`);
|
|
@@ -1755,12 +1632,28 @@ var EntitySandbox = class {
|
|
|
1755
1632
|
const current = this.state.entities.find((entity) => entity.entity_id === input.entity_id);
|
|
1756
1633
|
if (current === void 0) throw new Error(`Unknown entity "${input.entity_id}"`);
|
|
1757
1634
|
assembleEntityContent(toDslRows(this.state), createEntityId(input.entity_id));
|
|
1635
|
+
const payload = {
|
|
1636
|
+
...current.payload,
|
|
1637
|
+
...input.payload
|
|
1638
|
+
};
|
|
1639
|
+
const rows = toDslRows({
|
|
1640
|
+
...this.state,
|
|
1641
|
+
entities: this.state.entities.map((row) => row.entity_id === input.entity_id ? {
|
|
1642
|
+
...row,
|
|
1643
|
+
payload
|
|
1644
|
+
} : row)
|
|
1645
|
+
});
|
|
1646
|
+
for (const row of rows.entities) assembleEntityContent(rows, row.entityId);
|
|
1647
|
+
const assembled = assembleEntityContent(rows, createEntityId(input.entity_id));
|
|
1648
|
+
const issues = validateEntity(createEntityRef({
|
|
1649
|
+
...assembled.payload,
|
|
1650
|
+
entityId: assembled.entityId,
|
|
1651
|
+
entityKind: assembled.entityKind
|
|
1652
|
+
}));
|
|
1653
|
+
if (issues.length) throw new Error(issues.map((issue) => issue.message).join("; "));
|
|
1758
1654
|
this.replaceOwnedPayload({
|
|
1759
1655
|
entity_id: input.entity_id,
|
|
1760
|
-
payload
|
|
1761
|
-
...current.payload,
|
|
1762
|
-
...input.payload
|
|
1763
|
-
}
|
|
1656
|
+
payload
|
|
1764
1657
|
});
|
|
1765
1658
|
},
|
|
1766
1659
|
delete: (input) => this.deleteEntity(input),
|
|
@@ -1780,7 +1673,8 @@ var EntitySandbox = class {
|
|
|
1780
1673
|
linkClipAnchor: (input) => this.linkClipAnchor(input),
|
|
1781
1674
|
linkPhoneticScriptRender: (input) => this.linkPhoneticScriptRender(input),
|
|
1782
1675
|
linkAudioScriptSource: (input) => this.linkAudioScriptSource(input),
|
|
1783
|
-
unlink: (input) => this.unlinkRelation(input)
|
|
1676
|
+
unlink: (input) => this.unlinkRelation(input),
|
|
1677
|
+
update: (input) => this.changeRelation(input)
|
|
1784
1678
|
};
|
|
1785
1679
|
}
|
|
1786
1680
|
createEntity(input) {
|
|
@@ -1804,10 +1698,6 @@ var EntitySandbox = class {
|
|
|
1804
1698
|
}
|
|
1805
1699
|
const entityId = input.entity_id ?? this.idFactory("entity");
|
|
1806
1700
|
assertTrimmed(entityId, "entity_id");
|
|
1807
|
-
if (input.entity_kind === "audio-script") {
|
|
1808
|
-
const existing = this.state.entities.find((entity) => entity.entity_kind === "audio-script");
|
|
1809
|
-
if (existing !== void 0 && existing.entity_id !== entityId) throw new Error(`Editor requires exactly one AudioScript; edit ${existing.entity_id} instead of creating ${entityId}`);
|
|
1810
|
-
}
|
|
1811
1701
|
const entity = {
|
|
1812
1702
|
entity_id: entityId,
|
|
1813
1703
|
entity_kind: input.entity_kind,
|
|
@@ -1818,6 +1708,10 @@ var EntitySandbox = class {
|
|
|
1818
1708
|
entityId: createEntityId(entityId),
|
|
1819
1709
|
entityKind: entity.entity_kind
|
|
1820
1710
|
});
|
|
1711
|
+
assembleEntityContent(toDslRows({
|
|
1712
|
+
...this.state,
|
|
1713
|
+
entities: [...this.state.entities, entity]
|
|
1714
|
+
}), createEntityId(entityId));
|
|
1821
1715
|
this.record({
|
|
1822
1716
|
kind: "create-entity",
|
|
1823
1717
|
entity
|
|
@@ -1848,6 +1742,22 @@ var EntitySandbox = class {
|
|
|
1848
1742
|
payload
|
|
1849
1743
|
});
|
|
1850
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
|
+
}
|
|
1851
1761
|
deleteEntity(input) {
|
|
1852
1762
|
assertTrimmed(input.entity_id, "entity_id");
|
|
1853
1763
|
this.record({
|
|
@@ -1893,12 +1803,11 @@ var EntitySandbox = class {
|
|
|
1893
1803
|
}
|
|
1894
1804
|
}
|
|
1895
1805
|
link(input) {
|
|
1896
|
-
if (input.relation_kind === "generated") throw new Error("Author generated Relations with relations.linkGenerated({ output_entity_id, input_entity_id })");
|
|
1897
1806
|
const spec = builtInRelationSpecs.find((candidate) => candidate.kind === input.relation_kind);
|
|
1898
1807
|
if (spec == null) throw new Error(`Unknown Relation kind "${String(input.relation_kind)}"`);
|
|
1899
1808
|
const relation = this.relationFromInput(input, input.relation_kind);
|
|
1900
1809
|
const [first, second] = this.refsFor(relation);
|
|
1901
|
-
new BiRelationIndex().
|
|
1810
|
+
new BiRelationIndex().linkRuntime({
|
|
1902
1811
|
relationId: createRelationId(relation.relation_id),
|
|
1903
1812
|
spec,
|
|
1904
1813
|
endpoints: [first, second],
|
|
@@ -2036,10 +1945,9 @@ var EntitySandbox = class {
|
|
|
2036
1945
|
apply(command, enforceIdentity) {
|
|
2037
1946
|
switch (command.kind) {
|
|
2038
1947
|
case "create-entity": {
|
|
2039
|
-
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");
|
|
2040
1948
|
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`);
|
|
2041
1949
|
const original = this.original.entities.find((entity) => entity.entity_id === command.entity.entity_id);
|
|
2042
|
-
if (enforceIdentity && original != null
|
|
1950
|
+
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}"`);
|
|
2043
1951
|
this.state.entities.push(clone(command.entity));
|
|
2044
1952
|
if (command.entity.entity_kind === "audio-script" && this.state.audioScriptEntityId === null) this.state.audioScriptEntityId = command.entity.entity_id;
|
|
2045
1953
|
return;
|
|
@@ -2055,8 +1963,66 @@ var EntitySandbox = class {
|
|
|
2055
1963
|
};
|
|
2056
1964
|
return;
|
|
2057
1965
|
}
|
|
1966
|
+
case "change-entity": {
|
|
1967
|
+
const original = this.state;
|
|
1968
|
+
this.state = cloneSnapshot(original);
|
|
1969
|
+
try {
|
|
1970
|
+
const touched = new Set([command.entity_id]);
|
|
1971
|
+
for (const change of command.changes) {
|
|
1972
|
+
if (change.path[0] === "baseEntityIds" && change.op === "list.move") throw new Error("Composition bases are unordered; list.move is not applicable");
|
|
1973
|
+
const owner = resolveEntityFieldOwner(toDslRows(this.state), createEntityId(command.entity_id), change.path[0]);
|
|
1974
|
+
const row = this.state.entities.find((row) => row.entity_id === owner);
|
|
1975
|
+
row.payload = applyFieldChanges(row.payload, [change]);
|
|
1976
|
+
touched.add(owner);
|
|
1977
|
+
}
|
|
1978
|
+
const rows = toDslRows(this.state);
|
|
1979
|
+
for (const row of rows.entities) {
|
|
1980
|
+
const assembled = assembleEntityContent(rows, row.entityId);
|
|
1981
|
+
if (touched.has(row.entityId)) {
|
|
1982
|
+
const issues = validateEntity(createEntityRef({
|
|
1983
|
+
...assembled.payload,
|
|
1984
|
+
entityId: row.entityId,
|
|
1985
|
+
entityKind: row.entityKind
|
|
1986
|
+
}));
|
|
1987
|
+
if (issues.length) throw new Error(issues.map((issue) => issue.message).join("; "));
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
} catch (error) {
|
|
1991
|
+
this.state = original;
|
|
1992
|
+
throw error;
|
|
1993
|
+
}
|
|
1994
|
+
return;
|
|
1995
|
+
}
|
|
1996
|
+
case "change-relation": {
|
|
1997
|
+
const index = this.state.relations.findIndex((row) => row.relation_id === command.relation_id);
|
|
1998
|
+
if (index < 0) throw new Error(`Unknown relation ${command.relation_id}`);
|
|
1999
|
+
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");
|
|
2000
|
+
const current = this.state.relations[index];
|
|
2001
|
+
const fields = applyFieldChanges({
|
|
2002
|
+
metadata: current.metadata,
|
|
2003
|
+
trace: current.trace
|
|
2004
|
+
}, command.changes);
|
|
2005
|
+
const next = {
|
|
2006
|
+
...current,
|
|
2007
|
+
metadata: fields.metadata,
|
|
2008
|
+
trace: fields.trace
|
|
2009
|
+
};
|
|
2010
|
+
const spec = builtInRelationSpecs.find((spec) => spec.kind === next.relation_kind);
|
|
2011
|
+
new BiRelationIndex().linkRuntime({
|
|
2012
|
+
relationId: createRelationId(next.relation_id),
|
|
2013
|
+
spec,
|
|
2014
|
+
endpoints: this.refsFor(next),
|
|
2015
|
+
metadata: next.metadata,
|
|
2016
|
+
trace: next.trace
|
|
2017
|
+
});
|
|
2018
|
+
this.state.relations[index] = next;
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2058
2021
|
case "delete-entity": {
|
|
2059
|
-
|
|
2022
|
+
const target = this.state.entities.find((entity) => entity.entity_id === command.entity_id);
|
|
2023
|
+
if (target && (target.entity_kind === "timeline" || target.entity_id === this.state.audioScriptEntityId)) throw new Error("An entity attached to the project editor cannot be deleted");
|
|
2024
|
+
const dependents = this.state.entities.filter((entity) => Array.isArray(entity.payload.baseEntityIds) && entity.payload.baseEntityIds.includes(command.entity_id));
|
|
2025
|
+
if (dependents.length) throw new Error(`Entity ${command.entity_id} is still referenced by variants: ${dependents.map((row) => row.entity_id).join(", ")}`);
|
|
2060
2026
|
const index = this.state.entities.findIndex((entity) => entity.entity_id === command.entity_id);
|
|
2061
2027
|
if (index < 0) throw new Error(`Entity id "${command.entity_id}" does not exist`);
|
|
2062
2028
|
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();
|
|
@@ -2130,350 +2096,6 @@ const numericMarkerComparators = { compareMarkerPoints: (_marker, _range, left,
|
|
|
2130
2096
|
return left - right;
|
|
2131
2097
|
} };
|
|
2132
2098
|
//#endregion
|
|
2133
|
-
|
|
2134
|
-
const LOG_LINE_MAX = 2e3;
|
|
2135
|
-
const LOG_LINE_CAP = 1e3;
|
|
2136
|
-
const LOG_BYTE_CAP = 64 * 1024;
|
|
2137
|
-
const TRUNCATE_MARK = "[truncated]";
|
|
2138
|
-
const LOG_TRUNCATED = "[log truncated]";
|
|
2139
|
-
const ENTITY_CHECKPOINT_INDEX = Symbol("entityCheckpointIndex");
|
|
2140
|
-
/** Session core for one forked document; globals stay identity-stable across rollback. */
|
|
2141
|
-
var EditSandboxSession = class {
|
|
2142
|
-
original;
|
|
2143
|
-
idFactory;
|
|
2144
|
-
onEntry;
|
|
2145
|
-
onLog;
|
|
2146
|
-
onTruncate;
|
|
2147
|
-
entitySandbox;
|
|
2148
|
-
current;
|
|
2149
|
-
/** Adapter journal length already accounted for — new slices are real commits. */
|
|
2150
|
-
adapterJournalSeen = 0;
|
|
2151
|
-
entries = [];
|
|
2152
|
-
logs = [];
|
|
2153
|
-
logBytes = 0;
|
|
2154
|
-
logCapped = false;
|
|
2155
|
-
edit;
|
|
2156
|
-
timeline;
|
|
2157
|
-
entities;
|
|
2158
|
-
relations;
|
|
2159
|
-
console;
|
|
2160
|
-
checkpoint;
|
|
2161
|
-
rollbackTo;
|
|
2162
|
-
constructor(document, options) {
|
|
2163
|
-
this.original = structuredClone(document);
|
|
2164
|
-
this.idFactory = options?.idFactory;
|
|
2165
|
-
this.onEntry = options?.onEntry;
|
|
2166
|
-
this.onLog = options?.onLog;
|
|
2167
|
-
this.onTruncate = options?.onTruncate;
|
|
2168
|
-
this.entitySandbox = new EntitySandbox({
|
|
2169
|
-
state: options?.entityState,
|
|
2170
|
-
idFactory: options?.domainIdFactory ?? (() => {
|
|
2171
|
-
throw new Error("Entity id factory is unavailable in this sandbox host");
|
|
2172
|
-
}),
|
|
2173
|
-
onCommand: options?.onEntityCommand,
|
|
2174
|
-
onTruncate: options?.onEntityTruncate
|
|
2175
|
-
});
|
|
2176
|
-
this.current = this.boot(structuredClone(this.original));
|
|
2177
|
-
this.adapterJournalSeen = this.current.adapter.journal.length;
|
|
2178
|
-
this.edit = this.buildEditFacade();
|
|
2179
|
-
this.timeline = this.buildTimelineFacade();
|
|
2180
|
-
this.entities = this.entitySandbox.entities;
|
|
2181
|
-
this.relations = this.entitySandbox.relations;
|
|
2182
|
-
this.console = this.buildConsoleShim();
|
|
2183
|
-
this.checkpoint = () => {
|
|
2184
|
-
const checkpoint = { index: this.entries.length };
|
|
2185
|
-
Object.defineProperty(checkpoint, ENTITY_CHECKPOINT_INDEX, {
|
|
2186
|
-
value: this.entitySandbox.commandCount,
|
|
2187
|
-
enumerable: false
|
|
2188
|
-
});
|
|
2189
|
-
return checkpoint;
|
|
2190
|
-
};
|
|
2191
|
-
this.rollbackTo = (cp) => this.doRollbackTo(cp);
|
|
2192
|
-
}
|
|
2193
|
-
/** Assemble a ChangePlan from the self-maintained journal + current preview. */
|
|
2194
|
-
buildPlan(baseVersion) {
|
|
2195
|
-
const entityCommands = this.entitySandbox.getCommands();
|
|
2196
|
-
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");
|
|
2197
|
-
const entityPlan = this.entitySandbox.buildPlan();
|
|
2198
|
-
const planKind = entityCommands.length > 0 ? "entities" : "timeline";
|
|
2199
|
-
return {
|
|
2200
|
-
plan_kind: planKind,
|
|
2201
|
-
doc_id: this.original.meta.draft_id ?? "",
|
|
2202
|
-
base_version: baseVersion,
|
|
2203
|
-
ops: this.entries.slice(),
|
|
2204
|
-
entity_base_revision: entityPlan.base_revision,
|
|
2205
|
-
entity_commands: entityPlan.commands,
|
|
2206
|
-
...planKind === "entities" ? { entity_rows: entityPlan.rows } : {},
|
|
2207
|
-
...planKind === "entities" ? {
|
|
2208
|
-
deleted_entity_ids: entityPlan.deleted_entity_ids,
|
|
2209
|
-
deleted_relation_ids: entityPlan.deleted_relation_ids
|
|
2210
|
-
} : {},
|
|
2211
|
-
preview: planKind === "entities" ? this.entitySandbox.renderPreview() : renderPreview(this.current.adapter.snapshot(), this.entries),
|
|
2212
|
-
logs: this.logs.slice()
|
|
2213
|
-
};
|
|
2214
|
-
}
|
|
2215
|
-
getEntries() {
|
|
2216
|
-
return this.entries;
|
|
2217
|
-
}
|
|
2218
|
-
getLogs() {
|
|
2219
|
-
return this.logs;
|
|
2220
|
-
}
|
|
2221
|
-
boot(document) {
|
|
2222
|
-
const sandbox = createEditSandbox(document, this.idFactory != null ? { idFactory: this.idFactory } : void 0);
|
|
2223
|
-
return {
|
|
2224
|
-
adapter: sandbox.adapter,
|
|
2225
|
-
editor: sandbox.editor
|
|
2226
|
-
};
|
|
2227
|
-
}
|
|
2228
|
-
doRollbackTo(cp) {
|
|
2229
|
-
if (cp.index > this.entries.length) throw new Error(`rollbackTo: checkpoint index ${cp.index} is past journal length ${this.entries.length}`);
|
|
2230
|
-
const prefix = this.entries.slice(0, cp.index);
|
|
2231
|
-
const next = this.boot(structuredClone(this.original));
|
|
2232
|
-
replayJournalSync(next.adapter, prefix);
|
|
2233
|
-
this.entries.length = 0;
|
|
2234
|
-
this.entries.push(...prefix);
|
|
2235
|
-
this.current = next;
|
|
2236
|
-
this.adapterJournalSeen = next.adapter.journal.length;
|
|
2237
|
-
this.onTruncate?.(prefix.length);
|
|
2238
|
-
const entityIndex = cp[ENTITY_CHECKPOINT_INDEX];
|
|
2239
|
-
if (entityIndex !== void 0) this.entitySandbox.rollbackTo(entityIndex);
|
|
2240
|
-
}
|
|
2241
|
-
captureNewEntries() {
|
|
2242
|
-
const journal = this.current.adapter.journal;
|
|
2243
|
-
if (journal.length <= this.adapterJournalSeen) return;
|
|
2244
|
-
const fresh = journal.slice(this.adapterJournalSeen);
|
|
2245
|
-
this.adapterJournalSeen = journal.length;
|
|
2246
|
-
for (const entry of fresh) {
|
|
2247
|
-
this.entries.push(entry);
|
|
2248
|
-
this.onEntry?.(entry);
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
appendLog(line) {
|
|
2252
|
-
if (this.logCapped) return;
|
|
2253
|
-
if (this.logs.length >= LOG_LINE_CAP || this.logBytes >= LOG_BYTE_CAP) {
|
|
2254
|
-
this.logs.push(LOG_TRUNCATED);
|
|
2255
|
-
this.logCapped = true;
|
|
2256
|
-
this.onLog?.(LOG_TRUNCATED);
|
|
2257
|
-
return;
|
|
2258
|
-
}
|
|
2259
|
-
let out = line;
|
|
2260
|
-
if (out.length > LOG_LINE_MAX) out = `${out.slice(0, LOG_LINE_MAX - 11)}${TRUNCATE_MARK}`;
|
|
2261
|
-
this.logs.push(out);
|
|
2262
|
-
this.logBytes += out.length;
|
|
2263
|
-
this.onLog?.(out);
|
|
2264
|
-
}
|
|
2265
|
-
buildConsoleShim() {
|
|
2266
|
-
const write = (...args) => {
|
|
2267
|
-
this.appendLog(args.map(formatLogArg).join(" "));
|
|
2268
|
-
};
|
|
2269
|
-
return {
|
|
2270
|
-
log: write,
|
|
2271
|
-
info: write,
|
|
2272
|
-
warn: write,
|
|
2273
|
-
error: write
|
|
2274
|
-
};
|
|
2275
|
-
}
|
|
2276
|
-
buildEditFacade() {
|
|
2277
|
-
const wrap = (method) => async (input) => {
|
|
2278
|
-
await method(this.current.editor, input);
|
|
2279
|
-
this.captureNewEntries();
|
|
2280
|
-
};
|
|
2281
|
-
return {
|
|
2282
|
-
addSpeeches: wrap((e, i) => e.addSpeeches(i)),
|
|
2283
|
-
addVideoClips: async (input) => {
|
|
2284
|
-
const needsAppend = input.before_clip_id == null && input.after_clip_id == null && input.clips.some((clip) => clip.start_ms == null);
|
|
2285
|
-
const appendAt = this.timeline.snapshot().timeline?.duration_ms ?? 0;
|
|
2286
|
-
const normalized = needsAppend ? {
|
|
2287
|
-
...input,
|
|
2288
|
-
clips: input.clips.map((clip) => clip.start_ms == null ? {
|
|
2289
|
-
...clip,
|
|
2290
|
-
start_ms: appendAt
|
|
2291
|
-
} : clip)
|
|
2292
|
-
} : input;
|
|
2293
|
-
await this.current.editor.addVideoClips(normalized);
|
|
2294
|
-
this.captureNewEntries();
|
|
2295
|
-
},
|
|
2296
|
-
adjustBgmVolume: wrap((e, i) => e.adjustBgmVolume(i)),
|
|
2297
|
-
adjustSpeechVolume: wrap((e, i) => e.adjustSpeechVolume(i)),
|
|
2298
|
-
adjustVideoClipDuration: wrap((e, i) => e.adjustVideoClipDuration(i)),
|
|
2299
|
-
adjustVideoClipVolume: wrap((e, i) => e.adjustVideoClipVolume(i)),
|
|
2300
|
-
changeSpeechScript: wrap((e, i) => e.changeSpeechScript(i)),
|
|
2301
|
-
changeSpeechVoice: wrap((e, i) => e.changeSpeechVoice(i)),
|
|
2302
|
-
deleteBgm: wrap((e, i) => e.deleteBgm(i)),
|
|
2303
|
-
deleteSpeeches: wrap((e, i) => e.deleteSpeeches(i)),
|
|
2304
|
-
deleteVideoClips: wrap((e, i) => e.deleteVideoClips(i)),
|
|
2305
|
-
moveSpeeches: wrap((e, i) => e.moveSpeeches(i)),
|
|
2306
|
-
moveVideoClips: wrap((e, i) => e.moveVideoClips(i)),
|
|
2307
|
-
moveVideoClipsByAnchor: wrap((e, i) => e.moveVideoClipsByAnchor(i)),
|
|
2308
|
-
replaceVideoClipContent: wrap((e, i) => e.replaceVideoClipContent(i)),
|
|
2309
|
-
replaceVideoClipSequence: wrap((e, i) => e.replaceVideoClipSequence(i)),
|
|
2310
|
-
setBgm: wrap((e, i) => e.setBgm(i)),
|
|
2311
|
-
setCaptionStyle: wrap((e, i) => e.setCaptionStyle(i)),
|
|
2312
|
-
setCaptionVisibility: wrap((e, i) => e.setCaptionVisibility(i)),
|
|
2313
|
-
setVideoClipSpeedShift: wrap((e, i) => e.setVideoClipSpeedShift(i))
|
|
2314
|
-
};
|
|
2315
|
-
}
|
|
2316
|
-
buildTimelineFacade() {
|
|
2317
|
-
return {
|
|
2318
|
-
snapshot: () => fromVideoDocument(this.current.adapter.snapshot()),
|
|
2319
|
-
clipsInRange: (startMs, endMs) => this.clipsInRange(startMs, endMs),
|
|
2320
|
-
part: (id) => this.part(id)
|
|
2321
|
-
};
|
|
2322
|
-
}
|
|
2323
|
-
clipsInRange(startMs, endMs) {
|
|
2324
|
-
const document = this.current.adapter.snapshot();
|
|
2325
|
-
const solved = solveVideoDocument(document);
|
|
2326
|
-
const library = document.part_library ?? {};
|
|
2327
|
-
const main = document.tracks?.find((track) => track.parts_kind === "video_clip");
|
|
2328
|
-
const out = [];
|
|
2329
|
-
for (const item of main?.items ?? []) {
|
|
2330
|
-
const id = item.part_id;
|
|
2331
|
-
if (id == null) continue;
|
|
2332
|
-
const clip = library[id]?.video_clip;
|
|
2333
|
-
if (clip == null) continue;
|
|
2334
|
-
const start = solved.absByPartId.get(id) ?? 0;
|
|
2335
|
-
const duration = effectiveVideoClipDurationMs(clip);
|
|
2336
|
-
const end = start + duration;
|
|
2337
|
-
const mid = start + duration / 2;
|
|
2338
|
-
if (!(mid >= startMs && mid < endMs)) continue;
|
|
2339
|
-
out.push({
|
|
2340
|
-
id,
|
|
2341
|
-
start_ms: start,
|
|
2342
|
-
end_ms: end,
|
|
2343
|
-
duration_ms: duration,
|
|
2344
|
-
speed_shift: clip.speed_shift,
|
|
2345
|
-
volume: clip.volume,
|
|
2346
|
-
media_id: clip.origin_media_id
|
|
2347
|
-
});
|
|
2348
|
-
}
|
|
2349
|
-
return out;
|
|
2350
|
-
}
|
|
2351
|
-
part(id) {
|
|
2352
|
-
const document = this.current.adapter.snapshot();
|
|
2353
|
-
const part = (document.part_library ?? {})[id];
|
|
2354
|
-
if (part == null) return null;
|
|
2355
|
-
let lane = "main";
|
|
2356
|
-
let kind = "video_clip";
|
|
2357
|
-
for (const track of document.tracks ?? []) {
|
|
2358
|
-
if (!(track.items ?? []).some((item) => item.part_id === id)) continue;
|
|
2359
|
-
const partsKind = track.parts_kind ?? "video_clip";
|
|
2360
|
-
kind = partsKind;
|
|
2361
|
-
lane = partsKind === "video_clip" ? "main" : partsKind;
|
|
2362
|
-
break;
|
|
2363
|
-
}
|
|
2364
|
-
const solved = solveVideoDocument(document);
|
|
2365
|
-
const start = solved.absByPartId.get(id) ?? 0;
|
|
2366
|
-
let duration = 0;
|
|
2367
|
-
if (part.video_clip != null) duration = effectiveVideoClipDurationMs(part.video_clip);
|
|
2368
|
-
else if (part.speech != null) duration = part.speech.media_duration_ms ?? 0;
|
|
2369
|
-
else if (part.caption != null) duration = part.caption.initial_duration_ms ?? 0;
|
|
2370
|
-
else if (part.bgm != null) duration = solved.durationMs;
|
|
2371
|
-
return {
|
|
2372
|
-
id,
|
|
2373
|
-
kind,
|
|
2374
|
-
lane,
|
|
2375
|
-
start_ms: start,
|
|
2376
|
-
end_ms: start + duration,
|
|
2377
|
-
duration_ms: duration,
|
|
2378
|
-
part
|
|
2379
|
-
};
|
|
2380
|
-
}
|
|
2381
|
-
};
|
|
2382
|
-
function formatLogArg(value) {
|
|
2383
|
-
if (typeof value === "string") return value;
|
|
2384
|
-
if (typeof value === "number" || typeof value === "boolean" || value === null || value === void 0) return String(value);
|
|
2385
|
-
try {
|
|
2386
|
-
return JSON.stringify(value);
|
|
2387
|
-
} catch {
|
|
2388
|
-
return "[unstringifiable]";
|
|
2389
|
-
}
|
|
2390
|
-
}
|
|
2391
|
-
/**
|
|
2392
|
-
* Synchronous journal replay for rollback. Editor methods are `async` only for
|
|
2393
|
-
* interface uniformity — their bodies complete before the Promise is returned,
|
|
2394
|
-
* so voiding the call applies mutations in-order without yielding.
|
|
2395
|
-
*/
|
|
2396
|
-
function replayJournalSync(adapter, journal) {
|
|
2397
|
-
const queue = [];
|
|
2398
|
-
const idFactory = (_prefix) => {
|
|
2399
|
-
const id = queue.shift();
|
|
2400
|
-
if (id == null) throw new Error("unrecorded id");
|
|
2401
|
-
return id;
|
|
2402
|
-
};
|
|
2403
|
-
const editor = new SemanticEditor(adapter, new SchemaValidator(), idFactory);
|
|
2404
|
-
for (const entry of journal) {
|
|
2405
|
-
queue.push(...entry.generated_ids ?? []);
|
|
2406
|
-
const payload = entry.payload;
|
|
2407
|
-
switch (entry.kind) {
|
|
2408
|
-
case "MoveVideoClips":
|
|
2409
|
-
editor.moveVideoClips(payload);
|
|
2410
|
-
break;
|
|
2411
|
-
case "MoveVideoClipsByAnchor":
|
|
2412
|
-
editor.moveVideoClipsByAnchor(payload);
|
|
2413
|
-
break;
|
|
2414
|
-
case "DeleteVideoClips":
|
|
2415
|
-
editor.deleteVideoClips(payload);
|
|
2416
|
-
break;
|
|
2417
|
-
case "AddVideoClips":
|
|
2418
|
-
editor.addVideoClips(payload);
|
|
2419
|
-
break;
|
|
2420
|
-
case "AdjustVideoClipVolume":
|
|
2421
|
-
editor.adjustVideoClipVolume(payload);
|
|
2422
|
-
break;
|
|
2423
|
-
case "SetVideoClipSpeedShift":
|
|
2424
|
-
editor.setVideoClipSpeedShift(payload);
|
|
2425
|
-
break;
|
|
2426
|
-
case "ReplaceVideoClipContent":
|
|
2427
|
-
editor.replaceVideoClipContent(payload);
|
|
2428
|
-
break;
|
|
2429
|
-
case "ReplaceVideoClipSequence":
|
|
2430
|
-
editor.replaceVideoClipSequence(payload);
|
|
2431
|
-
break;
|
|
2432
|
-
case "AdjustVideoClipDuration":
|
|
2433
|
-
editor.adjustVideoClipDuration(payload);
|
|
2434
|
-
break;
|
|
2435
|
-
case "AddSpeeches":
|
|
2436
|
-
editor.addSpeeches(payload);
|
|
2437
|
-
break;
|
|
2438
|
-
case "DeleteSpeeches":
|
|
2439
|
-
editor.deleteSpeeches(payload);
|
|
2440
|
-
break;
|
|
2441
|
-
case "MoveSpeeches":
|
|
2442
|
-
editor.moveSpeeches(payload);
|
|
2443
|
-
break;
|
|
2444
|
-
case "ChangeSpeechScript":
|
|
2445
|
-
editor.changeSpeechScript(payload);
|
|
2446
|
-
break;
|
|
2447
|
-
case "ChangeSpeechVoice":
|
|
2448
|
-
editor.changeSpeechVoice(payload);
|
|
2449
|
-
break;
|
|
2450
|
-
case "AdjustSpeechVolume":
|
|
2451
|
-
editor.adjustSpeechVolume(payload);
|
|
2452
|
-
break;
|
|
2453
|
-
case "SetCaptionVisibility":
|
|
2454
|
-
editor.setCaptionVisibility(payload);
|
|
2455
|
-
break;
|
|
2456
|
-
case "SetCaptionStyle":
|
|
2457
|
-
editor.setCaptionStyle(payload);
|
|
2458
|
-
break;
|
|
2459
|
-
case "SetBgm":
|
|
2460
|
-
editor.setBgm(payload);
|
|
2461
|
-
break;
|
|
2462
|
-
case "DeleteBgm":
|
|
2463
|
-
editor.deleteBgm(payload);
|
|
2464
|
-
break;
|
|
2465
|
-
case "AdjustBgmVolume":
|
|
2466
|
-
editor.adjustBgmVolume(payload);
|
|
2467
|
-
break;
|
|
2468
|
-
default: {
|
|
2469
|
-
const _exhaustive = entry.kind;
|
|
2470
|
-
throw new Error(`replayJournalSync: unsupported kind ${String(_exhaustive)}`);
|
|
2471
|
-
}
|
|
2472
|
-
}
|
|
2473
|
-
if (queue.length > 0) throw new Error("unconsumed ids");
|
|
2474
|
-
}
|
|
2475
|
-
}
|
|
2476
|
-
//#endregion
|
|
2477
|
-
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 };
|
|
2099
|
+
export { createEntityId as a, businessState as i, toDslRows as n, createRelationId as o, businessFacades as r, isMediaAssetVariantKind as s, EntitySandbox as t };
|
|
2478
2100
|
|
|
2479
|
-
//# sourceMappingURL=
|
|
2101
|
+
//# sourceMappingURL=entity-sandbox-OArq9NSH.mjs.map
|