@mengine/medeo-client 2.0.1-alpha.25 → 2.0.1-alpha.27
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/dist/{document-Bx9xf40e.js → document-BGYPKtJ3.js} +41 -174
- package/dist/{index-BYv9FPSS.d.ts → index-CcIoMxs1.d.ts} +74 -339
- package/dist/index.d.ts +16 -82
- package/dist/index.js +31 -280
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +4 -4
|
@@ -2495,7 +2495,7 @@ const toAssetRelationSpec = Object.freeze({
|
|
|
2495
2495
|
validateEndpoints: (endpoints) => hasExactlyOneAsset(endpoints),
|
|
2496
2496
|
validateMetadata: isAssetBinding
|
|
2497
2497
|
});
|
|
2498
|
-
/** Media
|
|
2498
|
+
/** Media a generated medium can be made from, and a transcript can be read off. */
|
|
2499
2499
|
const MEDIA_VARIANT_KINDS = [
|
|
2500
2500
|
"video",
|
|
2501
2501
|
"image",
|
|
@@ -2517,7 +2517,7 @@ const derivedFromRelationSpec = Object.freeze({
|
|
|
2517
2517
|
kind: "derived-from",
|
|
2518
2518
|
ordered: true,
|
|
2519
2519
|
sequenced: false,
|
|
2520
|
-
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(MEDIA_VARIANT_KINDS), new Set(MEDIA_VARIANT_KINDS)) || hasKinds(endpoints, new Set(["voiceover-recording"]), new Set(["phonetic-script"])) || hasKinds(endpoints, new Set(["audio-script"]), new Set(MEDIA_AUDIBLE_KINDS))
|
|
2520
|
+
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(MEDIA_VARIANT_KINDS), new Set(MEDIA_VARIANT_KINDS)) || hasKinds(endpoints, new Set(["voiceover-recording"]), new Set(["phonetic-script"])) || hasKinds(endpoints, new Set(["audio-script"]), new Set(MEDIA_AUDIBLE_KINDS)),
|
|
2521
2521
|
validateMetadata: isEmptyMetadata
|
|
2522
2522
|
});
|
|
2523
2523
|
const captionAlignmentRelationSpec = Object.freeze({
|
|
@@ -2887,42 +2887,6 @@ function errorMessage(error) {
|
|
|
2887
2887
|
return error instanceof Error ? error.message : String(error);
|
|
2888
2888
|
}
|
|
2889
2889
|
//#endregion
|
|
2890
|
-
//#region ../medeo-dsl/src/relation-transition.ts
|
|
2891
|
-
var InvalidEntityRelationTransitionError = class extends Error {
|
|
2892
|
-
issues;
|
|
2893
|
-
constructor(issues) {
|
|
2894
|
-
super(`Invalid Medeo relation transition:\n- ${issues.join("\n- ")}`);
|
|
2895
|
-
this.issues = issues;
|
|
2896
|
-
this.name = "InvalidEntityRelationTransitionError";
|
|
2897
|
-
}
|
|
2898
|
-
};
|
|
2899
|
-
/** Enforce relation fact identity while admitting a complete candidate view. */
|
|
2900
|
-
function validateEntityRelationTransition(before, candidate) {
|
|
2901
|
-
const issues = [];
|
|
2902
|
-
const previous = new Map(before.relations.map((row) => [row.relationId, row]));
|
|
2903
|
-
for (const relation of candidate.relations) {
|
|
2904
|
-
const original = previous.get(relation.relationId);
|
|
2905
|
-
if (original == null) {
|
|
2906
|
-
if (relation.relationKind === "caption-alignment") issues.push(`new caption-alignment relation "${relation.relationId}" is forbidden`);
|
|
2907
|
-
continue;
|
|
2908
|
-
}
|
|
2909
|
-
if (original.relationKind !== relation.relationKind || original.endpoint0EntityId !== relation.endpoint0EntityId || original.endpoint1EntityId !== relation.endpoint1EntityId) {
|
|
2910
|
-
issues.push(`relation "${relation.relationId}" changed its kind or ordered endpoints`);
|
|
2911
|
-
continue;
|
|
2912
|
-
}
|
|
2913
|
-
if (!sameJson(original.metadata, relation.metadata)) issues.push(`relation "${relation.relationId}" changed semantic metadata without a new identity`);
|
|
2914
|
-
if (relation.relationKind === "caption-alignment" && !sameJson(original.trace, relation.trace)) issues.push(`legacy caption-alignment relation "${relation.relationId}" may only be carried unchanged or deleted`);
|
|
2915
|
-
}
|
|
2916
|
-
if (issues.length > 0) throw new InvalidEntityRelationTransitionError(issues);
|
|
2917
|
-
}
|
|
2918
|
-
function sameJson(left, right) {
|
|
2919
|
-
if (left === right) return true;
|
|
2920
|
-
if (Array.isArray(left) && Array.isArray(right)) return left.length === right.length && left.every((value, index) => sameJson(value, right[index]));
|
|
2921
|
-
if (!isJsonObject(left) || !isJsonObject(right)) return false;
|
|
2922
|
-
const leftKeys = Object.keys(left);
|
|
2923
|
-
return leftKeys.length === Object.keys(right).length && leftKeys.every((key) => Object.hasOwn(right, key) && sameJson(left[key], right[key]));
|
|
2924
|
-
}
|
|
2925
|
-
//#endregion
|
|
2926
2890
|
//#region src/document/entity-projection-values.ts
|
|
2927
2891
|
/** A graph cannot be represented faithfully by the compatibility reader. */
|
|
2928
2892
|
var EntityTimelineProjectionError = class extends Error {
|
|
@@ -2991,8 +2955,19 @@ var EntityProjectionGraph = class {
|
|
|
2991
2955
|
heldBy(id) {
|
|
2992
2956
|
return this.rows.relations.filter((row) => row.relationKind === "contain" && row.endpoint1EntityId === id).map((row) => this.entity(row.endpoint0EntityId));
|
|
2993
2957
|
}
|
|
2994
|
-
|
|
2995
|
-
|
|
2958
|
+
/**
|
|
2959
|
+
* Ordered relations put the product at endpoint 0 and its source at endpoint 1.
|
|
2960
|
+
* One entity can sit on both sides of the same kind — a Voiceover Recording is
|
|
2961
|
+
* spoken from a PhoneticScript and is itself what a transcript was read from —
|
|
2962
|
+
* so provenance is never read through the undirected `adjacent`.
|
|
2963
|
+
*/
|
|
2964
|
+
madeFrom(id, kind) {
|
|
2965
|
+
return this.rows.relations.filter((row) => row.relationKind === kind && row.endpoint0EntityId === id).map((row) => this.entity(row.endpoint1EntityId));
|
|
2966
|
+
}
|
|
2967
|
+
madeInto(id, kind) {
|
|
2968
|
+
return this.rows.relations.filter((row) => row.relationKind === kind && row.endpoint1EntityId === id).map((row) => this.entity(row.endpoint0EntityId));
|
|
2969
|
+
}
|
|
2970
|
+
one(id, relation, kind, values = this.adjacent(id, relation)) {
|
|
2996
2971
|
if (values.length !== 1 || kind !== void 0 && values[0]?.entityKind !== kind) fail(`entity ${id} requires exactly one ${relation}${kind === void 0 ? "" : ` to ${kind}`}`);
|
|
2997
2972
|
return values[0];
|
|
2998
2973
|
}
|
|
@@ -3028,7 +3003,7 @@ function resolveGraphLayout(graph) {
|
|
|
3028
3003
|
const held = graph.holds(clip.entityId);
|
|
3029
3004
|
if (held.length !== 1) fail(`Clip ${clip.entityId} must contain exactly one content entity`);
|
|
3030
3005
|
const content = held[0];
|
|
3031
|
-
const expected = typedRole === "video_clip" ? ["image", "video"] : typedRole === "speech" ? ["voiceover-recording"
|
|
3006
|
+
const expected = typedRole === "video_clip" ? ["image", "video"] : typedRole === "speech" ? ["voiceover-recording"] : typedRole === "caption" ? ["caption"] : ["audio"];
|
|
3032
3007
|
if (!expected.includes(content.entityKind)) fail(`${typedRole} Track accepts ${expected.join(" or ")}, got ${content.entityKind}`);
|
|
3033
3008
|
const inMs = milliseconds(marker.payload.inMs, "inMs");
|
|
3034
3009
|
const outMs = milliseconds(marker.payload.outMs, "outMs");
|
|
@@ -3178,12 +3153,12 @@ function projectEntityTimeline(rows) {
|
|
|
3178
3153
|
} else if (track.role === "speech") {
|
|
3179
3154
|
const asset = mediaAssetFacts(graph, content);
|
|
3180
3155
|
requireUntrimmedAudio(content, marker, placement);
|
|
3181
|
-
const
|
|
3182
|
-
const
|
|
3156
|
+
const external = externalLocator(asset, "memota-speech");
|
|
3157
|
+
const renderEdges = graph.madeFrom(content.entityId, "derived-from");
|
|
3183
3158
|
const timbreEdges = graph.adjacent(content.entityId, "voice-timbre");
|
|
3184
|
-
const assembled =
|
|
3185
|
-
const transcript = synthesized ? void 0 : transcribedAudioScript(graph, content);
|
|
3159
|
+
const assembled = renderEdges.length > 0 || timbreEdges.length > 0 ? assemblePhoneticScriptContent(rows, graph.one(content.entityId, "derived-from", "phonetic-script", renderEdges).entityId) : void 0;
|
|
3186
3160
|
if (timbreEdges.length > 1) fail("A voiceover resolves at most one Voice identity");
|
|
3161
|
+
const transcripts = graph.madeInto(content.entityId, "derived-from");
|
|
3187
3162
|
const voice = timbreEdges.length === 0 ? void 0 : graph.one(content.entityId, "voice-timbre", "voice").payload.voice;
|
|
3188
3163
|
if (voice !== void 0 && (!object(voice) || voice.system !== "voice-library" || typeof voice.key !== "string")) fail("Voice must use an explicit voice-library locator");
|
|
3189
3164
|
const captionIds = layout.tracks.flatMap((candidate) => candidate.role === "caption" ? candidate.clips.filter((caption) => caption.anchorClipEntityId === clip.entityId).map((caption) => caption.clipEntityId) : []);
|
|
@@ -3193,7 +3168,7 @@ function projectEntityTimeline(rows) {
|
|
|
3193
3168
|
media_duration_ms: placement.duration,
|
|
3194
3169
|
audio_storage_key: storageKey(asset),
|
|
3195
3170
|
origin_speech_id: external.key,
|
|
3196
|
-
audio_script: assembled?.text ?? (
|
|
3171
|
+
audio_script: assembled?.text ?? (transcripts.length > 0 ? assembleScriptText(graph.one(content.entityId, "derived-from", "audio-script", transcripts)) : ""),
|
|
3197
3172
|
volume: volume.data,
|
|
3198
3173
|
voice: object(voice) ? {
|
|
3199
3174
|
id: typeof voice.key === "string" ? voice.key : void 0,
|
|
@@ -3312,17 +3287,7 @@ function captionStyle(value) {
|
|
|
3312
3287
|
}
|
|
3313
3288
|
function requireUntrimmedAudio(content, marker, placement) {
|
|
3314
3289
|
const source = markerWindow(marker);
|
|
3315
|
-
if (source.start !== 0 || content.payload.durationMs !== source.end || placement.duration !== source.end || marker.payload.rate !== void 0) fail("
|
|
3316
|
-
}
|
|
3317
|
-
function synthesizedPhoneticScript(graph, content) {
|
|
3318
|
-
const scripts = graph.rows.relations.filter((row) => row.relationKind === "derived-from" && row.endpoint0EntityId === content.entityId).map((row) => graph.entity(row.endpoint1EntityId)).filter((row) => row.entityKind === "phonetic-script");
|
|
3319
|
-
if (scripts.length !== 1) fail("Synthesized Speech requires exactly one ordered PhoneticScript input");
|
|
3320
|
-
return scripts[0];
|
|
3321
|
-
}
|
|
3322
|
-
function transcribedAudioScript(graph, content) {
|
|
3323
|
-
const scripts = graph.rows.relations.filter((row) => row.relationKind === "derived-from" && row.endpoint1EntityId === content.entityId).map((row) => graph.entity(row.endpoint0EntityId)).filter((row) => row.entityKind === "audio-script");
|
|
3324
|
-
if (scripts.length > 1) fail("Recorded Speech has ambiguous AudioScript transcripts");
|
|
3325
|
-
return scripts[0];
|
|
3290
|
+
if (source.start !== 0 || content.payload.durationMs !== source.end || placement.duration !== source.end || marker.payload.rate !== void 0) fail("Voiceover compatibility requires the complete, unremapped take");
|
|
3326
3291
|
}
|
|
3327
3292
|
/** The Marker's window, in the {start,end} shape this compatibility reader speaks. */
|
|
3328
3293
|
function markerWindow(marker) {
|
|
@@ -3731,19 +3696,6 @@ function writeEntityOrder(doc, group, roots, token) {
|
|
|
3731
3696
|
//#region src/entity-crdt/entity-document.ts
|
|
3732
3697
|
const LORO_ENTITY_SCHEMA = "medeo.entities.loro.v1";
|
|
3733
3698
|
const MATERIALIZE_ORIGIN = "medeo.materialize";
|
|
3734
|
-
/** Read persisted relation roots before current entity versions are projected. */
|
|
3735
|
-
function readEntityRelationRecords(doc) {
|
|
3736
|
-
if (root(doc).get("schema") !== "medeo.entities.loro.v1") throw new Error("Document has no Loro entity state");
|
|
3737
|
-
return relationRecords(doc).map(({ rootId, identity, map, deleted }) => ({
|
|
3738
|
-
relationId: createRelationId(rootId),
|
|
3739
|
-
relationKind: identity.kind,
|
|
3740
|
-
endpoint0EntityId: createEntityId(identity.endpoints[0]),
|
|
3741
|
-
endpoint1EntityId: createEntityId(identity.endpoints[1]),
|
|
3742
|
-
metadata: requireMap(map, "metadata").toJSON(),
|
|
3743
|
-
trace: requireMap(map, "trace").toJSON(),
|
|
3744
|
-
deleted
|
|
3745
|
-
}));
|
|
3746
|
-
}
|
|
3747
3699
|
function hash(value) {
|
|
3748
3700
|
return bytesToHex(sha256(new TextEncoder().encode(canonicalJson(value))));
|
|
3749
3701
|
}
|
|
@@ -3830,31 +3782,35 @@ function readEntityDocument(doc, allowSelectionConflicts = false) {
|
|
|
3830
3782
|
}
|
|
3831
3783
|
};
|
|
3832
3784
|
});
|
|
3833
|
-
const relations =
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3785
|
+
const relations = [];
|
|
3786
|
+
for (const key of section(doc, "relations").keys().sort((a, b) => a < b ? -1 : a > b ? 1 : 0)) {
|
|
3787
|
+
const map = section(doc, "relations").get(key);
|
|
3788
|
+
if (!(map instanceof LoroMap) || map.get("deleted") === true) continue;
|
|
3789
|
+
const original = map.get("identity");
|
|
3790
|
+
if (original.endpoints.some((id) => !ids.has(family(doc, id)))) continue;
|
|
3791
|
+
const endpoints = original.endpoints.map((id) => currentId(doc, id, ids));
|
|
3792
|
+
const relationId = equalJson(endpoints, original.endpoints) ? key : `relation_${hash([key, endpoints])}`;
|
|
3793
|
+
relations.push({
|
|
3794
|
+
relationId: createRelationId(relationId),
|
|
3795
|
+
relationKind: original.kind,
|
|
3838
3796
|
endpoint0EntityId: createEntityId(endpoints[0]),
|
|
3839
3797
|
endpoint1EntityId: createEntityId(endpoints[1]),
|
|
3840
3798
|
metadata: requireMap(map, "metadata").toJSON(),
|
|
3841
3799
|
trace: requireMap(map, "trace").toJSON()
|
|
3842
|
-
};
|
|
3843
|
-
}
|
|
3800
|
+
});
|
|
3801
|
+
}
|
|
3844
3802
|
sortSequencedRelations(doc, relations);
|
|
3845
3803
|
const project = {};
|
|
3846
3804
|
for (const [key, value] of Object.entries(section(doc, "attachments").toJSON())) {
|
|
3847
3805
|
if (typeof value !== "string") throw new Error(`Invalid project attachment ${key}`);
|
|
3848
3806
|
project[key] = currentId(doc, value, ids);
|
|
3849
3807
|
}
|
|
3850
|
-
const phoneticScriptSelections = readPhoneticScriptSelections(doc, ids);
|
|
3851
3808
|
const state = {
|
|
3852
3809
|
rows: {
|
|
3853
3810
|
entities,
|
|
3854
3811
|
relations
|
|
3855
3812
|
},
|
|
3856
|
-
project
|
|
3857
|
-
...phoneticScriptSelections === void 0 ? {} : { phoneticScriptSelections }
|
|
3813
|
+
project
|
|
3858
3814
|
};
|
|
3859
3815
|
if (!allowSelectionConflicts) for (const [key, id] of ids) {
|
|
3860
3816
|
const fingerprint = selectionFingerprint(state.rows, id);
|
|
@@ -3862,54 +3818,6 @@ function readEntityDocument(doc, allowSelectionConflicts = false) {
|
|
|
3862
3818
|
}
|
|
3863
3819
|
return state;
|
|
3864
3820
|
}
|
|
3865
|
-
function readPhoneticScriptSelections(doc, ids) {
|
|
3866
|
-
const native = root(doc).get("phoneticScriptSelections");
|
|
3867
|
-
if (native === void 0) return void 0;
|
|
3868
|
-
if (!(native instanceof LoroMap)) throw new Error("Invalid phonetic-script selector");
|
|
3869
|
-
const selections = {};
|
|
3870
|
-
for (const clipRoot of native.keys().sort((a, b) => a < b ? -1 : a > b ? 1 : 0)) {
|
|
3871
|
-
const phoneticScriptRoot = native.get(clipRoot);
|
|
3872
|
-
if (typeof phoneticScriptRoot !== "string") throw new Error("Invalid phonetic-script selection");
|
|
3873
|
-
const clipId = ids.get(clipRoot);
|
|
3874
|
-
const phoneticScriptId = ids.get(phoneticScriptRoot);
|
|
3875
|
-
if (clipId === void 0 || phoneticScriptId === void 0) continue;
|
|
3876
|
-
if (workspace(doc, clipRoot).get("kind") !== "clip") throw new Error("Phonetic-script selection target must be a Clip");
|
|
3877
|
-
if (workspace(doc, phoneticScriptRoot).get("kind") !== "phonetic-script") throw new Error("Phonetic-script selection value must be a PhoneticScript");
|
|
3878
|
-
selections[clipRoot] = phoneticScriptId;
|
|
3879
|
-
}
|
|
3880
|
-
return Object.keys(selections).length === 0 ? void 0 : selections;
|
|
3881
|
-
}
|
|
3882
|
-
function relationRecords(doc) {
|
|
3883
|
-
const records = [];
|
|
3884
|
-
for (const rootId of section(doc, "relations").keys().sort((a, b) => a < b ? -1 : a > b ? 1 : 0)) {
|
|
3885
|
-
const map = section(doc, "relations").get(rootId);
|
|
3886
|
-
if (!(map instanceof LoroMap)) throw new Error(`Invalid relation record ${rootId}`);
|
|
3887
|
-
const value = map.get("identity");
|
|
3888
|
-
if (!isJsonObject(value) || typeof value.kind !== "string" || !Array.isArray(value.endpoints) || value.endpoints.length !== 2 || !value.endpoints.every((endpoint) => typeof endpoint === "string")) throw new Error(`Invalid relation identity ${rootId}`);
|
|
3889
|
-
records.push({
|
|
3890
|
-
rootId,
|
|
3891
|
-
identity: {
|
|
3892
|
-
kind: value.kind,
|
|
3893
|
-
endpoints: [value.endpoints[0], value.endpoints[1]]
|
|
3894
|
-
},
|
|
3895
|
-
map,
|
|
3896
|
-
deleted: map.get("deleted") === true
|
|
3897
|
-
});
|
|
3898
|
-
}
|
|
3899
|
-
return records;
|
|
3900
|
-
}
|
|
3901
|
-
function activeRelationRecords(doc, ids) {
|
|
3902
|
-
const selector = root(doc).get("clipContentSelections");
|
|
3903
|
-
if (selector !== void 0 && !(selector instanceof LoroMap)) throw new Error("Invalid clip-content selector");
|
|
3904
|
-
return relationRecords(doc).filter(({ rootId, identity, deleted }) => {
|
|
3905
|
-
if (deleted) return false;
|
|
3906
|
-
if (!identity.endpoints.every((id) => ids.has(family(doc, id)))) return false;
|
|
3907
|
-
if (identity.kind !== "contain" || selector === void 0 || workspace(doc, family(doc, identity.endpoints[0])).get("kind") !== "clip") return true;
|
|
3908
|
-
const selected = selector.get(family(doc, identity.endpoints[0]));
|
|
3909
|
-
if (selected !== void 0 && typeof selected !== "string") throw new Error("Invalid clip-content selection");
|
|
3910
|
-
return selected === void 0 || selected === rootId;
|
|
3911
|
-
});
|
|
3912
|
-
}
|
|
3913
3821
|
/** Native editing containers survive domain version changes and merge independently. */
|
|
3914
3822
|
var LoroEntityDocument = class LoroEntityDocument {
|
|
3915
3823
|
doc;
|
|
@@ -3941,9 +3849,7 @@ var LoroEntityDocument = class LoroEntityDocument {
|
|
|
3941
3849
|
"relations",
|
|
3942
3850
|
"project",
|
|
3943
3851
|
"attachments",
|
|
3944
|
-
"ordering"
|
|
3945
|
-
"clipContentSelections",
|
|
3946
|
-
"phoneticScriptSelections"
|
|
3852
|
+
"ordering"
|
|
3947
3853
|
]) root(doc).ensureMergeableMap(name);
|
|
3948
3854
|
for (const row of rows.entities) apply(doc, {
|
|
3949
3855
|
type: "create",
|
|
@@ -4147,14 +4053,11 @@ var LoroEntityDraft = class {
|
|
|
4147
4053
|
row: clone(row)
|
|
4148
4054
|
});
|
|
4149
4055
|
}
|
|
4150
|
-
|
|
4151
|
-
const relation = this.snapshot().rows.relations.find((row) => row.relationId === relationId);
|
|
4152
|
-
if (relation == null) throw new Error(`Unknown relation ${relationId}`);
|
|
4153
|
-
if (relation.relationKind === "caption-alignment") throw new Error("caption-alignment Relations are read-only legacy facts");
|
|
4056
|
+
patchRelation(relationId, metadata, trace) {
|
|
4154
4057
|
this.record({
|
|
4155
4058
|
type: "relation-fields",
|
|
4156
4059
|
root: this.relationRoot(relationId),
|
|
4157
|
-
metadata: clone(
|
|
4060
|
+
metadata: clone(metadata),
|
|
4158
4061
|
trace: clone(trace)
|
|
4159
4062
|
});
|
|
4160
4063
|
}
|
|
@@ -4164,35 +4067,6 @@ var LoroEntityDraft = class {
|
|
|
4164
4067
|
root: this.relationRoot(relationId)
|
|
4165
4068
|
});
|
|
4166
4069
|
}
|
|
4167
|
-
/** Select the one content membership projected for this stable Clip identity. */
|
|
4168
|
-
selectClipContent(relationId) {
|
|
4169
|
-
const relationRoot = this.relationRoot(relationId);
|
|
4170
|
-
const map = section(this.doc, "relations").get(relationRoot);
|
|
4171
|
-
if (!(map instanceof LoroMap)) throw new Error(`Unknown relation ${relationId}`);
|
|
4172
|
-
const identity = map.get("identity");
|
|
4173
|
-
if (!isJsonObject(identity) || identity.kind !== "contain" || !Array.isArray(identity.endpoints) || typeof identity.endpoints[0] !== "string") throw new Error("Clip-content selection requires a contain relation");
|
|
4174
|
-
const clipRoot = family(this.doc, identity.endpoints[0]);
|
|
4175
|
-
if (workspace(this.doc, clipRoot).get("kind") !== "clip") throw new Error("Clip-content selection requires a Clip container");
|
|
4176
|
-
this.record({
|
|
4177
|
-
type: "select-clip-content",
|
|
4178
|
-
clipRoot,
|
|
4179
|
-
relationRoot
|
|
4180
|
-
});
|
|
4181
|
-
}
|
|
4182
|
-
/** Select the pending immutable pronunciation variant for one stable Speech Clip. */
|
|
4183
|
-
selectPhoneticScript(clipEntityId, phoneticScriptEntityId) {
|
|
4184
|
-
const clipRoot = family(this.doc, clipEntityId);
|
|
4185
|
-
const phoneticScriptRoot = family(this.doc, phoneticScriptEntityId);
|
|
4186
|
-
const clip = workspace(this.doc, clipRoot);
|
|
4187
|
-
const phoneticScript = workspace(this.doc, phoneticScriptRoot);
|
|
4188
|
-
if (clip.get("deleted") === true || clip.get("kind") !== "clip") throw new Error("Phonetic-script selection target must be an active Clip");
|
|
4189
|
-
if (phoneticScript.get("deleted") === true || phoneticScript.get("kind") !== "phonetic-script") throw new Error("Phonetic-script selection value must be an active PhoneticScript");
|
|
4190
|
-
this.record({
|
|
4191
|
-
type: "select-phonetic-script",
|
|
4192
|
-
clipRoot,
|
|
4193
|
-
phoneticScriptRoot
|
|
4194
|
-
});
|
|
4195
|
-
}
|
|
4196
4070
|
relationRoot(relationId) {
|
|
4197
4071
|
const alias = this.relationAliases.get(relationId);
|
|
4198
4072
|
if (alias !== void 0) return alias;
|
|
@@ -4279,9 +4153,8 @@ var LoroEntityDraft = class {
|
|
|
4279
4153
|
const key = this.relationRoot(relationId);
|
|
4280
4154
|
const map = section(this.doc, "relations").get(key);
|
|
4281
4155
|
if (!(map instanceof LoroMap) || map.get("deleted") === true) throw new Error("Unknown relation");
|
|
4282
|
-
if (map.get("identity").kind === "caption-alignment") throw new Error("caption-alignment Relations are read-only legacy facts");
|
|
4283
4156
|
for (const change of changes) {
|
|
4284
|
-
if (change.path[0]
|
|
4157
|
+
if (!["metadata", "trace"].includes(change.path[0]) || change.path.length < 2) throw new Error("Relation changes may only edit metadata or trace fields");
|
|
4285
4158
|
const payload = {
|
|
4286
4159
|
metadata: requireMap(map, "metadata").toJSON(),
|
|
4287
4160
|
trace: requireMap(map, "trace").toJSON()
|
|
@@ -4400,12 +4273,6 @@ function apply(doc, command) {
|
|
|
4400
4273
|
map.set("deleted", true);
|
|
4401
4274
|
break;
|
|
4402
4275
|
}
|
|
4403
|
-
case "select-clip-content":
|
|
4404
|
-
root(doc).ensureMergeableMap("clipContentSelections").set(command.clipRoot, command.relationRoot);
|
|
4405
|
-
break;
|
|
4406
|
-
case "select-phonetic-script":
|
|
4407
|
-
root(doc).ensureMergeableMap("phoneticScriptSelections").set(command.clipRoot, command.phoneticScriptRoot);
|
|
4408
|
-
break;
|
|
4409
4276
|
case "relation-fields": {
|
|
4410
4277
|
const map = section(doc, "relations").get(command.root);
|
|
4411
4278
|
if (!(map instanceof LoroMap)) throw new Error("Unknown relation");
|
|
@@ -4827,4 +4694,4 @@ function createPlainMemoryAdapter(document, options) {
|
|
|
4827
4694
|
return new PlainMemoryAdapter(document, options);
|
|
4828
4695
|
}
|
|
4829
4696
|
//#endregion
|
|
4830
|
-
export {
|
|
4697
|
+
export { assertValidVideoDocument as $, decodeEntityRelationRows as A, updateEntityFields as B, applyFieldChanges as C, speedOf as Ct, EntityProjectionGraph as D, base64ToBytes as Dt, projectEntityTimeline as E, videoDocumentMirrorSchema as Et, assembleEntityContent as F, hasSequence as G, isJsonObject as H, assemblePhoneticScriptContent as I, buildSpeechHostMap as J, isMediaAssetVariantKind as K, assembleScriptText as L, relationsTo as M, ScriptCompositionError as N, resolveEntityTimelineLayout as O, bytesToBase64 as Ot, assembleCaptionContent as P, VideoDocumentValidationError as Q, findComposedAudioScript as R, equalJson as S, effectiveVideoClipDurationMs as St, resolveFieldPath as T, recordEntries as Tt, createEntityId as U, variantBaseEntityIds as V, createRelationId as W, fromVideoDocument as X, derivePositionFromAbs as Y, toVideoDocument as Z, audioScriptAssetOf as _, TIMELINE_SKELETON_DURATION_MS as _t, createMirrorVideoDocument as a, findLaneTrack as at, phoneticScriptAssetOf as b, safeDurationMs as bt, DocumentMutationGuard as c, solveVideoDocument as ct, LoroEntityDraft as d, fillMainTrackTimeGaps as dt, validateVideoDocument as et, readEntityDocument as f, reassignSpeechesToVideoClipsByTime as ft, audioScriptAssetHash as g, syncAggregatedClipsTimePosition as gt, audioScriptAssetFields as h, resolveSpeechOverlapByShiftingVideos as ht, MirrorVideoDocumentAdapter as i, ensureLaneTrack as it, relationsFrom as j, EntityTimelineProjectionError as k, LORO_ENTITY_SCHEMA as l, cascadeAfterVideoClipChanges as lt, audioScriptAssetContent as m, resolveAllSpeechOverlaps as mt, createPlainMemoryAdapter as n, videoDocumentSchema as nt, createMirrorVideoDocumentAdapter as o, hasResolvedPlacement as ot, entityOrderGroups as p, recalculateTimelineDuration as pt, buildInitialVideoDocument as q, generatePartId as r, LANE_KINDS_IN_STACK_ORDER as rt, readVideoDocumentFromDraft as s, laneTrackId as st, PlainMemoryAdapter as t, partUnionSchema as tt, LoroEntityDocument as u, arrangeMainTrackSeamlessly as ut, phoneticScriptAssetContent as v, isEmptyVideoClip as vt, assertFieldChanges as w, partUnionToDraft as wt, scriptSourceAssetOf as x, DEFAULT_UNIT_TIME_MS as xt, phoneticScriptAssetHash as y, partDurationMs as yt, selectAudioScriptSegment as z };
|