@mengine/medeo-client 2.0.1-alpha.13 → 2.0.1-alpha.14
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-CAZ_A9R8.js → document-BHHbS_17.js} +34 -86
- package/dist/{index-BZtSciyB.d.ts → index-qAoWdqvp.d.ts} +1 -1
- package/dist/index.d.ts +396 -192
- package/dist/index.js +1439 -81
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +4 -4
|
@@ -1462,9 +1462,8 @@ function emptyLaneTracks() {
|
|
|
1462
1462
|
* `Voice` declares no `Sequence` — it is a timbre identity, not playable
|
|
1463
1463
|
* content; a rendered voiceover is an `audio` entity.
|
|
1464
1464
|
*
|
|
1465
|
-
*
|
|
1466
|
-
*
|
|
1467
|
-
* flowed, is the `from-asset` / `to-asset` Relation's answer alone.
|
|
1465
|
+
* No declaration says anything about resources: whether an entity has one, and
|
|
1466
|
+
* which, is the `from-asset` Relation's answer alone.
|
|
1468
1467
|
*/
|
|
1469
1468
|
const ENTITY_KINDS = Object.freeze({
|
|
1470
1469
|
axvideo: Object.freeze([
|
|
@@ -1481,27 +1480,27 @@ const ENTITY_KINDS = Object.freeze({
|
|
|
1481
1480
|
"Sequence",
|
|
1482
1481
|
"Visual",
|
|
1483
1482
|
"Audible",
|
|
1484
|
-
"
|
|
1483
|
+
"FromAsset"
|
|
1485
1484
|
]),
|
|
1486
1485
|
audio: Object.freeze([
|
|
1487
1486
|
"Sequence",
|
|
1488
1487
|
"Audible",
|
|
1489
|
-
"
|
|
1488
|
+
"FromAsset"
|
|
1490
1489
|
]),
|
|
1491
1490
|
image: Object.freeze([
|
|
1492
1491
|
"Sequence",
|
|
1493
1492
|
"Visual",
|
|
1494
|
-
"
|
|
1493
|
+
"FromAsset"
|
|
1495
1494
|
]),
|
|
1496
1495
|
voice: Object.freeze(["Container", "IPBound"]),
|
|
1497
1496
|
"sequence-marker": Object.freeze([]),
|
|
1498
1497
|
viewport: Object.freeze([]),
|
|
1499
|
-
"audio-script": Object.freeze(["SegmentText", "
|
|
1500
|
-
"phonetic-script": Object.freeze(["SegmentText"
|
|
1498
|
+
"audio-script": Object.freeze(["SegmentText", "FromAsset"]),
|
|
1499
|
+
"phonetic-script": Object.freeze(["SegmentText"]),
|
|
1501
1500
|
caption: Object.freeze([
|
|
1502
1501
|
"SegmentText",
|
|
1503
1502
|
"Sequence",
|
|
1504
|
-
"
|
|
1503
|
+
"FromAsset"
|
|
1505
1504
|
])
|
|
1506
1505
|
});
|
|
1507
1506
|
/** What a known kind declares; extension kinds declare nothing through this table. */
|
|
@@ -1799,6 +1798,15 @@ function entityToRow(entity) {
|
|
|
1799
1798
|
//#endregion
|
|
1800
1799
|
//#region ../medeo-dsl/src/invariants.ts
|
|
1801
1800
|
/** An entity is made from at most one Asset; two would leave its bytes ambiguous. */
|
|
1801
|
+
function validateAssetSource(entity, index) {
|
|
1802
|
+
if (entity.current().entityKind === "asset") return [];
|
|
1803
|
+
if ([...index.relationsOf(entity)].filter((relation) => relation.kind === "from-asset").length <= 1) return [];
|
|
1804
|
+
return [{
|
|
1805
|
+
code: "asset_source_cardinality",
|
|
1806
|
+
entityId: entity.entityId,
|
|
1807
|
+
message: `Entity "${entity.entityId}" is made from more than one Asset`
|
|
1808
|
+
}];
|
|
1809
|
+
}
|
|
1802
1810
|
/** Validates one complete set of entities and its authoritative Relation rows. */
|
|
1803
1811
|
function validateEntityRelationSet(entityRefs, index, options) {
|
|
1804
1812
|
const { entities, issues } = collectRelatedEntities(entityRefs, index);
|
|
@@ -1820,6 +1828,7 @@ function validateEntityRelationSet(entityRefs, index, options) {
|
|
|
1820
1828
|
const current = entity.current();
|
|
1821
1829
|
const entityIssues = validateEntity(entity, entityIds);
|
|
1822
1830
|
issues.push(...entityIssues);
|
|
1831
|
+
issues.push(...validateAssetSource(entity, index));
|
|
1823
1832
|
if (entityIssues.some((issue) => issue.code === "invalid_entity_payload")) continue;
|
|
1824
1833
|
if (current.entityKind === "sequence-marker") {
|
|
1825
1834
|
const marker = entity;
|
|
@@ -2463,10 +2472,10 @@ const markerContentRelationSpec = Object.freeze({
|
|
|
2463
2472
|
/**
|
|
2464
2473
|
* `from-asset(entity, asset)` — the entity was made from that stored resource.
|
|
2465
2474
|
*
|
|
2466
|
-
* Eligibility is declared: the non-Asset endpoint must carry the `
|
|
2467
|
-
* which says an entity of that kind can be
|
|
2468
|
-
* nothing of its payload. The bytes stay named in exactly one place, so
|
|
2469
|
-
* entity copies the locator into its own row and one Asset can back several
|
|
2475
|
+
* Eligibility is declared: the non-Asset endpoint must carry the `FromAsset`
|
|
2476
|
+
* kind, which says an entity of that kind can be made from stored bytes and
|
|
2477
|
+
* asks nothing of its payload. The bytes stay named in exactly one place, so
|
|
2478
|
+
* no entity copies the locator into its own row and one Asset can back several
|
|
2470
2479
|
* entities.
|
|
2471
2480
|
*/
|
|
2472
2481
|
const fromAssetRelationSpec = Object.freeze({
|
|
@@ -2474,26 +2483,6 @@ const fromAssetRelationSpec = Object.freeze({
|
|
|
2474
2483
|
validateEndpoints: (endpoints) => hasExactlyOneAsset(endpoints),
|
|
2475
2484
|
validateMetadata: isAssetBinding
|
|
2476
2485
|
});
|
|
2477
|
-
/**
|
|
2478
|
-
* `to-asset(entity, asset)` — the entity's content was written out to that
|
|
2479
|
-
* stored resource.
|
|
2480
|
-
*
|
|
2481
|
-
* The mirror of `from-asset`, and deliberately a separate relation kind rather
|
|
2482
|
-
* than a second declared kind: eligibility is the same either way, but which
|
|
2483
|
-
* way the content flowed is what says whether an entity may still be edited.
|
|
2484
|
-
* An entity reached by `from-asset` was produced from bytes it does not own,
|
|
2485
|
-
* so changing it would contradict them. An entity with a `to-asset` owns its
|
|
2486
|
-
* content and the resource is a snapshot of it, which is what goes stale and
|
|
2487
|
-
* gets written again. A transcript that is later edited carries both at once,
|
|
2488
|
-
* and only the distinct relation kinds keep them apart.
|
|
2489
|
-
*
|
|
2490
|
-
* Writing a snapshot is host assembly; nothing a script authors creates one.
|
|
2491
|
-
*/
|
|
2492
|
-
const toAssetRelationSpec = Object.freeze({
|
|
2493
|
-
kind: "to-asset",
|
|
2494
|
-
validateEndpoints: (endpoints) => hasExactlyOneAsset(endpoints),
|
|
2495
|
-
validateMetadata: isAssetBinding
|
|
2496
|
-
});
|
|
2497
2486
|
/** `generated(output, input)` means endpoint 0 was generated from endpoint 1. */
|
|
2498
2487
|
const generatedRelationSpec = Object.freeze({
|
|
2499
2488
|
kind: "generated",
|
|
@@ -2556,7 +2545,6 @@ const builtInRelationSpecs = Object.freeze([
|
|
|
2556
2545
|
axVideoMarkerRelationSpec,
|
|
2557
2546
|
markerTimelineRelationSpec,
|
|
2558
2547
|
fromAssetRelationSpec,
|
|
2559
|
-
toAssetRelationSpec,
|
|
2560
2548
|
generatedRelationSpec,
|
|
2561
2549
|
captionAlignmentRelationSpec,
|
|
2562
2550
|
clipAnchorRelationSpec,
|
|
@@ -2585,12 +2573,12 @@ function hasMarkerAndSequence(endpoints) {
|
|
|
2585
2573
|
const second = endpoints[1].current();
|
|
2586
2574
|
return first.entityKind === "sequence-marker" && hasSequence(second) || second.entityKind === "sequence-marker" && hasSequence(first);
|
|
2587
2575
|
}
|
|
2588
|
-
/** Exactly one end is the Asset, so the other end is unambiguously the
|
|
2576
|
+
/** Exactly one end is the Asset, so the other end is unambiguously the maker. */
|
|
2589
2577
|
function hasExactlyOneAsset(endpoints) {
|
|
2590
2578
|
const kinds = endpoints.map((endpoint) => endpoint.current().entityKind);
|
|
2591
2579
|
const assets = kinds.map((kind) => kind === "asset");
|
|
2592
2580
|
if (assets[0] === assets[1]) return false;
|
|
2593
|
-
return declaresKind(assets[0] ? kinds[1] : kinds[0], "
|
|
2581
|
+
return declaresKind(assets[0] ? kinds[1] : kinds[0], "FromAsset");
|
|
2594
2582
|
}
|
|
2595
2583
|
function isGeneratedMedia(entity) {
|
|
2596
2584
|
return entity.entityKind === "video" || entity.entityKind === "image" || entity.entityKind === "audio";
|
|
@@ -3620,23 +3608,12 @@ function audioScriptAssetHash(payload) {
|
|
|
3620
3608
|
return bytesToHex(sha256(new TextEncoder().encode(canonicalJson(audioScriptAssetContent(payload)))));
|
|
3621
3609
|
}
|
|
3622
3610
|
/**
|
|
3623
|
-
* The Asset a script was written out to
|
|
3624
|
-
*
|
|
3625
|
-
*
|
|
3611
|
+
* The Asset a script was written out to, read from the graph rather than the
|
|
3612
|
+
* script's own row: like every other entity, a script names its bytes through
|
|
3613
|
+
* a `from-asset` Relation and stores no locator itself.
|
|
3626
3614
|
*/
|
|
3627
3615
|
function audioScriptAssetOf(rows, entityId) {
|
|
3628
|
-
|
|
3629
|
-
}
|
|
3630
|
-
/**
|
|
3631
|
-
* The Asset a script was made from — a transcript it does not own. A script
|
|
3632
|
-
* that has one never writes a snapshot of its own: the bytes it would describe
|
|
3633
|
-
* are already named, and rewriting them would contradict their source.
|
|
3634
|
-
*/
|
|
3635
|
-
function scriptSourceAssetOf(rows, entityId) {
|
|
3636
|
-
return boundAsset(rows, entityId, "from-asset");
|
|
3637
|
-
}
|
|
3638
|
-
function boundAsset(rows, entityId, relationKind) {
|
|
3639
|
-
const link = rows.relations.find((relation) => relation.relationKind === relationKind && (String(relation.endpoint0EntityId) === entityId || String(relation.endpoint1EntityId) === entityId));
|
|
3616
|
+
const link = rows.relations.find((relation) => relation.relationKind === "from-asset" && (String(relation.endpoint0EntityId) === entityId || String(relation.endpoint1EntityId) === entityId));
|
|
3640
3617
|
if (link === void 0) return void 0;
|
|
3641
3618
|
const otherId = String(link.endpoint0EntityId) === entityId ? link.endpoint1EntityId : link.endpoint0EntityId;
|
|
3642
3619
|
return rows.entities.find((row) => String(row.entityId) === String(otherId) && row.entityKind === "asset");
|
|
@@ -3645,33 +3622,6 @@ function boundAsset(rows, entityId, relationKind) {
|
|
|
3645
3622
|
function audioScriptAssetFields(payload) {
|
|
3646
3623
|
return { assetContentHash: audioScriptAssetHash(payload) };
|
|
3647
3624
|
}
|
|
3648
|
-
/**
|
|
3649
|
-
* What a PhoneticScript hands to synthesis: the base AudioScript's text as the
|
|
3650
|
-
* variant pronounces it, plus the variant's own phoneme and prosody control.
|
|
3651
|
-
*
|
|
3652
|
-
* The variant's content is written by a model — deciding how words are said is
|
|
3653
|
-
* text work, not a mechanical copy — but the bytes a synthesizer reads have to
|
|
3654
|
-
* leave the entity graph to reach it, because synthesis does not handle
|
|
3655
|
-
* entities. Writing this resource down is that crossing, and it is why speech
|
|
3656
|
-
* can only come from a PhoneticScript.
|
|
3657
|
-
*/
|
|
3658
|
-
function phoneticScriptAssetContent(rows, entityId) {
|
|
3659
|
-
const assembled = assemblePhoneticScriptContent(rows, createEntityId(entityId));
|
|
3660
|
-
const own = assembled.phoneticScript.payload;
|
|
3661
|
-
return {
|
|
3662
|
-
text: assembled.text,
|
|
3663
|
-
segments: structuredClone(assembled.segments),
|
|
3664
|
-
...typeof own.phonemeScript === "string" ? { phonemeScript: own.phonemeScript } : {},
|
|
3665
|
-
...isJsonObject(own.prosody) ? { prosody: structuredClone(own.prosody) } : {}
|
|
3666
|
-
};
|
|
3667
|
-
}
|
|
3668
|
-
function phoneticScriptAssetHash(rows, entityId) {
|
|
3669
|
-
return bytesToHex(sha256(new TextEncoder().encode(canonicalJson(phoneticScriptAssetContent(rows, entityId)))));
|
|
3670
|
-
}
|
|
3671
|
-
/** The Asset a PhoneticScript was written out to, read from the graph. */
|
|
3672
|
-
function phoneticScriptAssetOf(rows, entityId) {
|
|
3673
|
-
return audioScriptAssetOf(rows, entityId);
|
|
3674
|
-
}
|
|
3675
3625
|
//#endregion
|
|
3676
3626
|
//#region src/entity-crdt/ordering.ts
|
|
3677
3627
|
/** Domain order is scoped by membership; relation storage has no global order. */
|
|
@@ -3975,10 +3925,8 @@ var LoroEntityDocument = class LoroEntityDocument {
|
|
|
3975
3925
|
/**
|
|
3976
3926
|
* Bind a saved snapshot without rewriting text operations or resolving
|
|
3977
3927
|
* selection conflicts. The script names the bytes the same way everything
|
|
3978
|
-
* else does — an Asset entity plus a Relation — and keeps only
|
|
3979
|
-
* fingerprint that tells a stale snapshot from a current one.
|
|
3980
|
-
* `to-asset`: these bytes are the script's own content written out, not a
|
|
3981
|
-
* source it was made from.
|
|
3928
|
+
* else does — an Asset entity plus a `from-asset` Relation — and keeps only
|
|
3929
|
+
* the fingerprint that tells a stale snapshot from a current one.
|
|
3982
3930
|
*/
|
|
3983
3931
|
bindAudioScriptAsset(entityId, assetId, expectedContentHash) {
|
|
3984
3932
|
const key = family(this.doc, entityId);
|
|
@@ -4001,10 +3949,10 @@ var LoroEntityDocument = class LoroEntityDocument {
|
|
|
4001
3949
|
this.transact((draft) => {
|
|
4002
3950
|
const current = readEntityDocument(this.doc, true).rows;
|
|
4003
3951
|
if (audioScriptAssetOf(current, entityId)?.entityId !== assetEntityId) {
|
|
4004
|
-
for (const relation of current.relations) if (relation.relationKind === "
|
|
3952
|
+
for (const relation of current.relations) if (relation.relationKind === "from-asset" && (String(relation.endpoint0EntityId) === String(entityId) || String(relation.endpoint1EntityId) === String(entityId))) draft.unlink(String(relation.relationId));
|
|
4005
3953
|
draft.link({
|
|
4006
|
-
relationId: createRelationId(`
|
|
4007
|
-
relationKind: "
|
|
3954
|
+
relationId: createRelationId(`relation_from-asset_${entityId}_${assetId}`),
|
|
3955
|
+
relationKind: "from-asset",
|
|
4008
3956
|
endpoint0EntityId: createEntityId(entityId),
|
|
4009
3957
|
endpoint1EntityId: assetEntityId,
|
|
4010
3958
|
metadata: {},
|
|
@@ -4715,4 +4663,4 @@ function createPlainMemoryAdapter(document, options) {
|
|
|
4715
4663
|
return new PlainMemoryAdapter(document, options);
|
|
4716
4664
|
}
|
|
4717
4665
|
//#endregion
|
|
4718
|
-
export {
|
|
4666
|
+
export { ensureLaneTrack as $, assembleEntityContent as A, hasSequence as B, projectEntityTimeline as C, bytesToBase64 as Ct, decodeEntityRelationRows as D, EntityTimelineProjectionError as E, updateEntityFields as F, fromVideoDocument as G, buildInitialVideoDocument as H, variantBaseEntityIds as I, assertValidVideoDocument as J, toVideoDocument as K, isJsonObject as L, assembleScriptText as M, findComposedAudioScript as N, ScriptCompositionError as O, selectAudioScriptSegment as P, LANE_KINDS_IN_STACK_ORDER as Q, createEntityId as R, resolveFieldPath as S, base64ToBytes as St, resolveEntityTimelineLayout as T, buildSpeechHostMap as U, isMediaAssetVariantKind as V, derivePositionFromAbs as W, partUnionSchema as X, validateVideoDocument as Y, videoDocumentSchema as Z, audioScriptAssetOf as _, effectiveVideoClipDurationMs as _t, createMirrorVideoDocument as a, arrangeMainTrackSeamlessly as at, applyFieldChanges as b, recordEntries as bt, DocumentMutationGuard as c, recalculateTimelineDuration as ct, LoroEntityDraft as d, syncAggregatedClipsTimePosition as dt, findLaneTrack as et, readEntityDocument as f, TIMELINE_SKELETON_DURATION_MS as ft, audioScriptAssetHash as g, DEFAULT_UNIT_TIME_MS as gt, audioScriptAssetFields as h, safeDurationMs as ht, MirrorVideoDocumentAdapter as i, cascadeAfterVideoClipChanges as it, assemblePhoneticScriptContent as j, assembleCaptionContent as k, LORO_ENTITY_SCHEMA as l, resolveAllSpeechOverlaps as lt, audioScriptAssetContent as m, partDurationMs as mt, createPlainMemoryAdapter as n, laneTrackId as nt, createMirrorVideoDocumentAdapter as o, fillMainTrackTimeGaps as ot, entityOrderGroups as p, isEmptyVideoClip as pt, VideoDocumentValidationError as q, generatePartId as r, solveVideoDocument as rt, readVideoDocumentFromDraft as s, reassignSpeechesToVideoClipsByTime as st, PlainMemoryAdapter as t, hasResolvedPlacement as tt, LoroEntityDocument as u, resolveSpeechOverlapByShiftingVideos as ut, canonicalJson as v, speedOf as vt, EntityProjectionGraph as w, assertFieldChanges as x, videoDocumentMirrorSchema as xt, equalJson as y, partUnionToDraft as yt, createRelationId as z };
|
|
@@ -1104,7 +1104,7 @@ type CaptionSegmentSelection = JsonObject & {
|
|
|
1104
1104
|
};
|
|
1105
1105
|
//#endregion
|
|
1106
1106
|
//#region ../medeo-dsl/src/relations.d.ts
|
|
1107
|
-
type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'from-asset' | '
|
|
1107
|
+
type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'from-asset' | 'generated' | 'caption-alignment' | 'clip-anchor' | 'phonetic-script-render' | 'audio-script-source' | 'audio-script-marker';
|
|
1108
1108
|
type RelationKind = KnownRelationKind | (string & {});
|
|
1109
1109
|
type RelationTrace = JsonObject;
|
|
1110
1110
|
/**
|