@mengine/medeo-tool 2.0.1-alpha.6 → 2.0.1-alpha.8
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/{entity-contract-G4HxwNXl.d.mts → entity-contract-Bpe6NRIQ.d.mts} +23 -6
- package/dist/{entity-sandbox-DSFbfybl.mjs → entity-sandbox-CzaUmSsS.mjs} +104 -28
- package/dist/entity-sandbox-CzaUmSsS.mjs.map +1 -0
- package/dist/index.d.mts +21 -9
- package/dist/index.mjs +52 -47
- package/dist/index.mjs.map +1 -1
- package/dist/sandbox-api.d.mts +22 -5
- package/dist/worker-entry.d.mts +2 -1
- package/dist/worker-entry.mjs +24 -25
- package/dist/worker-entry.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/entity-sandbox-DSFbfybl.mjs.map +0 -1
|
@@ -8,8 +8,8 @@ interface JsonObject {
|
|
|
8
8
|
}
|
|
9
9
|
type KnownEntityKind = 'axvideo' | 'timeline' | 'track' | 'clip' | 'asset' | 'video' | 'audio' | 'voice' | 'image' | 'sequence-marker' | 'viewport' | 'audio-script' | 'phonetic-script' | 'caption';
|
|
10
10
|
/** Asset identity, either an old physical-only row or a directly composed media variant. */
|
|
11
|
-
type ResourceEntityKind = 'image' | 'video' | 'audio'
|
|
12
|
-
type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'physical-asset' | 'generated' | 'caption-alignment' | 'clip-anchor' | 'phonetic-script-render' | 'audio-script-source' | 'audio-script-marker';
|
|
11
|
+
type ResourceEntityKind = 'image' | 'video' | 'audio';
|
|
12
|
+
type KnownRelationKind = 'timeline-track' | 'track-clip' | 'clip-marker' | 'marker-content' | 'axvideo-marker' | 'marker-timeline' | 'physical-asset' | 'generated' | 'caption-alignment' | 'clip-anchor' | 'phonetic-script-render' | 'voice-timbre' | 'audio-script-source' | 'audio-script-marker';
|
|
13
13
|
type AuthorableRelationKind = KnownRelationKind;
|
|
14
14
|
interface BoundedNativeSequencePayload extends JsonObject {
|
|
15
15
|
/** Factual coordinates from recalled media metadata; never invent an end/duration. */
|
|
@@ -50,6 +50,14 @@ type MediaAssetPayload = JsonObject & {
|
|
|
50
50
|
};
|
|
51
51
|
storageKey?: string;
|
|
52
52
|
};
|
|
53
|
+
/** The voice-library timbre a synthesized Audio was rendered with. */
|
|
54
|
+
type VoiceIdentityPayload = JsonObject & {
|
|
55
|
+
voice: {
|
|
56
|
+
system: 'voice-library';
|
|
57
|
+
key: string;
|
|
58
|
+
name?: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
53
61
|
type CaptionTextSelection = JsonObject & {
|
|
54
62
|
segmentId: string; /** Half-open Unicode code-point range within the selected source segment. */
|
|
55
63
|
textRange?: {
|
|
@@ -68,8 +76,10 @@ interface EntityPayloadByKind {
|
|
|
68
76
|
/** Physical resource fields; never a copy of Caption content. */
|
|
69
77
|
asset: JsonObject;
|
|
70
78
|
video: BoundedNativeSequencePayload & MediaAssetPayload;
|
|
79
|
+
/** Every playable sound, including video original audio and synthesized voiceovers. */
|
|
71
80
|
audio: BoundedNativeSequencePayload & MediaAssetPayload;
|
|
72
|
-
|
|
81
|
+
/** A timbre identity, never playable content; the rendered take is an `audio` entity. */
|
|
82
|
+
voice: VoiceIdentityPayload;
|
|
73
83
|
image: UnboundedConstantSequencePayload & MediaAssetPayload;
|
|
74
84
|
'sequence-marker': JsonObject & {
|
|
75
85
|
sourceRange: {
|
|
@@ -115,8 +125,15 @@ interface EntityPayloadByKind {
|
|
|
115
125
|
}[];
|
|
116
126
|
};
|
|
117
127
|
}
|
|
118
|
-
/**
|
|
119
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Stored own fields; a variant may obtain required content fields from its
|
|
130
|
+
* declared bases.
|
|
131
|
+
*
|
|
132
|
+
* Caption and Audio may also be declared resource-only: the ASR transcript and
|
|
133
|
+
* the synthesized voiceover are attached by the host, which then fills in the
|
|
134
|
+
* remaining factual fields.
|
|
135
|
+
*/
|
|
136
|
+
type StoredEntityPayload<K extends KnownEntityKind> = EntityPayloadByKind[K] | (K extends 'caption' | 'audio' ? JsonObject & Pick<MediaAssetPayload, 'external'> : never) | (JsonObject & Partial<EntityPayloadByKind[K]> & {
|
|
120
137
|
baseEntityIds: string[];
|
|
121
138
|
});
|
|
122
139
|
interface SandboxEntity<K extends KnownEntityKind = KnownEntityKind> {
|
|
@@ -238,4 +255,4 @@ interface BusinessRelationFacade {
|
|
|
238
255
|
}
|
|
239
256
|
//#endregion
|
|
240
257
|
export { UpdateEntityInput as C, UnlinkRelationInput as S, LinkRelationInput as _, DeleteEntityInput as a, SandboxEntity as b, EntitySandboxCheckpoint as c, JsonObject as d, JsonPrimitive as f, LinkGeneratedRelationInput as g, KnownRelationKind as h, CreateEntityInput as i, EntityStoreSnapshot as l, KnownEntityKind as m, BusinessEntityFacade as n, EntityCommand as o, JsonValue as p, BusinessRelationFacade as r, EntityPlanState as s, AuthorableRelationKind as t, EntityUpdateInput as u, RelationUpdateInput as v, SandboxRelation as x, ResourceEntityKind as y };
|
|
241
|
-
//# sourceMappingURL=entity-contract-
|
|
258
|
+
//# sourceMappingURL=entity-contract-Bpe6NRIQ.d.mts.map
|
|
@@ -1,7 +1,62 @@
|
|
|
1
1
|
import { applyFieldChanges, assertCanonicalEditorResources, assertFieldChanges, ensureEditorFoundation, importMediaAsset, readDocumentAudioScript } from "@mengine/medeo-client";
|
|
2
2
|
//#region ../medeo-dsl/src/entities.ts
|
|
3
|
+
/**
|
|
4
|
+
* The declared trait set of every known kind.
|
|
5
|
+
*
|
|
6
|
+
* `caption` carries `sequence` on purpose: a Caption owns the display timing of
|
|
7
|
+
* the one AudioScript segment it shows, which is what admits it into a Clip.
|
|
8
|
+
* `voice` carries no media or sequence trait — it is a timbre identity, not
|
|
9
|
+
* playable content; a rendered voiceover is an `audio` entity.
|
|
10
|
+
*/
|
|
11
|
+
const ENTITY_TRAIT_KINDS = Object.freeze({
|
|
12
|
+
axvideo: Object.freeze([
|
|
13
|
+
"container",
|
|
14
|
+
"sequence",
|
|
15
|
+
"visual",
|
|
16
|
+
"audible"
|
|
17
|
+
]),
|
|
18
|
+
timeline: Object.freeze(["container"]),
|
|
19
|
+
track: Object.freeze(["container", "sequence"]),
|
|
20
|
+
clip: Object.freeze(["container"]),
|
|
21
|
+
asset: Object.freeze([]),
|
|
22
|
+
video: Object.freeze([
|
|
23
|
+
"media-file",
|
|
24
|
+
"sequence",
|
|
25
|
+
"visual",
|
|
26
|
+
"audible"
|
|
27
|
+
]),
|
|
28
|
+
audio: Object.freeze([
|
|
29
|
+
"media-file",
|
|
30
|
+
"sequence",
|
|
31
|
+
"audible"
|
|
32
|
+
]),
|
|
33
|
+
image: Object.freeze([
|
|
34
|
+
"media-file",
|
|
35
|
+
"sequence",
|
|
36
|
+
"visual"
|
|
37
|
+
]),
|
|
38
|
+
voice: Object.freeze(["container", "ip-bound"]),
|
|
39
|
+
"sequence-marker": Object.freeze([]),
|
|
40
|
+
viewport: Object.freeze([]),
|
|
41
|
+
"audio-script": Object.freeze(["segment-text"]),
|
|
42
|
+
"phonetic-script": Object.freeze(["segment-text"]),
|
|
43
|
+
caption: Object.freeze(["segment-text", "sequence"])
|
|
44
|
+
});
|
|
45
|
+
/** Declared traits of a known kind; extension kinds declare none through this table. */
|
|
46
|
+
function traitKindsOf(entityKind) {
|
|
47
|
+
return isKnownEntityKind(entityKind) ? ENTITY_TRAIT_KINDS[entityKind] : [];
|
|
48
|
+
}
|
|
49
|
+
function hasTraitKind(entityKind, trait) {
|
|
50
|
+
return traitKindsOf(entityKind).includes(trait);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Sequence admission asks the declared traits first, so a kind that does not
|
|
54
|
+
* declare `sequence` can never buy its way in by carrying the fields. Extension
|
|
55
|
+
* kinds declare no traits and stay structurally detected.
|
|
56
|
+
*/
|
|
3
57
|
function hasSequence(entity) {
|
|
4
|
-
if (
|
|
58
|
+
if (isReservedEntityKind(entity.entityKind)) return false;
|
|
59
|
+
if (isKnownEntityKind(entity.entityKind) && !hasTraitKind(entity.entityKind, "sequence")) return false;
|
|
5
60
|
return isSequenceFields(entity);
|
|
6
61
|
}
|
|
7
62
|
function isSequenceFields(value) {
|
|
@@ -14,22 +69,16 @@ function isSequenceFields(value) {
|
|
|
14
69
|
if (value.sampling !== "native" && value.sampling !== "constant" && value.sampling !== "derived") return false;
|
|
15
70
|
return "coordinateSpace" in value && value.coordinateSpace !== void 0;
|
|
16
71
|
}
|
|
17
|
-
function isKnownSequenceKind(kind) {
|
|
18
|
-
return isMediaAssetVariantKind(kind) || kind === "caption" || kind === "axvideo";
|
|
19
|
-
}
|
|
20
72
|
function isMediaAssetVariantKind(kind) {
|
|
21
|
-
return kind === "video" || kind === "image" || kind === "audio"
|
|
73
|
+
return kind === "video" || kind === "image" || kind === "audio";
|
|
22
74
|
}
|
|
23
75
|
function isKnownEntityKind(kind) {
|
|
24
|
-
return
|
|
76
|
+
return Object.hasOwn(ENTITY_TRAIT_KINDS, kind);
|
|
25
77
|
}
|
|
26
78
|
function isReservedEntityKind(kind) {
|
|
27
79
|
const normalized = kind.toLowerCase().replaceAll("-", "").replaceAll("_", "");
|
|
28
80
|
return normalized === "speech" || normalized === "videodocument";
|
|
29
81
|
}
|
|
30
|
-
function isKnownNonSequenceKind(kind) {
|
|
31
|
-
return kind === "timeline" || kind === "track" || kind === "clip" || kind === "asset" || kind === "sequence-marker" || kind === "viewport" || kind === "audio-script" || kind === "phonetic-script";
|
|
32
|
-
}
|
|
33
82
|
function isRecord$1(value) {
|
|
34
83
|
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
35
84
|
}
|
|
@@ -608,12 +657,15 @@ function validateKnownEntityPayload(entity) {
|
|
|
608
657
|
break;
|
|
609
658
|
case "video":
|
|
610
659
|
case "audio":
|
|
611
|
-
|
|
660
|
+
validateSequencePayload(value, "bounded", "native", problems);
|
|
661
|
+
validateMediaAssetFields(value, problems);
|
|
662
|
+
break;
|
|
612
663
|
case "caption":
|
|
613
664
|
validateSequencePayload(value, "bounded", "native", problems);
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
665
|
+
validateCaptionPayload(value, problems);
|
|
666
|
+
break;
|
|
667
|
+
case "voice":
|
|
668
|
+
validateVoicePayload(value, problems);
|
|
617
669
|
break;
|
|
618
670
|
case "image":
|
|
619
671
|
validateSequencePayload(value, "unbounded", "constant", problems);
|
|
@@ -720,11 +772,26 @@ function validateExternalLocator(value, problems) {
|
|
|
720
772
|
function validateStorageKey(value, problems) {
|
|
721
773
|
if (value.storageKey !== void 0 && (typeof value.storageKey !== "string" || value.storageKey.trim() === "")) problems.push("storageKey must be a non-empty string when present");
|
|
722
774
|
}
|
|
775
|
+
/**
|
|
776
|
+
* Voice is a timbre identity, not playable content: it owns the voice-library
|
|
777
|
+
* descriptor and nothing that would make it look like media or a Sequence. The
|
|
778
|
+
* rendered voiceover is an `audio` entity bound by a `voice-timbre` Relation.
|
|
779
|
+
*/
|
|
723
780
|
function validateVoicePayload(value, problems) {
|
|
781
|
+
for (const key of [
|
|
782
|
+
"extent",
|
|
783
|
+
"sampling",
|
|
784
|
+
"coordinateSpace",
|
|
785
|
+
"external",
|
|
786
|
+
"storageKey"
|
|
787
|
+
]) if (Object.hasOwn(value, key)) problems.push(`${key} belongs to the rendered Audio, not to the Voice identity`);
|
|
724
788
|
const voice = value.voice;
|
|
725
|
-
if (voice === void 0)
|
|
789
|
+
if (voice === void 0) {
|
|
790
|
+
problems.push("voice is required; a Voice entity is its voice-library identity");
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
726
793
|
if (!isRecord(voice)) {
|
|
727
|
-
problems.push("voice must be an object
|
|
794
|
+
problems.push("voice must be an object");
|
|
728
795
|
return;
|
|
729
796
|
}
|
|
730
797
|
if (voice.system !== "voice-library") problems.push("voice.system must be \"voice-library\"");
|
|
@@ -856,7 +923,6 @@ function isOwnedLocalEntityValuePath(entityKind, path) {
|
|
|
856
923
|
if ([
|
|
857
924
|
"video",
|
|
858
925
|
"audio",
|
|
859
|
-
"voice",
|
|
860
926
|
"image",
|
|
861
927
|
"caption",
|
|
862
928
|
"axvideo"
|
|
@@ -920,7 +986,7 @@ function collectRelatedEntities(entityRefs, index) {
|
|
|
920
986
|
};
|
|
921
987
|
}
|
|
922
988
|
function expectedSequenceShape(kind) {
|
|
923
|
-
if (kind === "video" || kind === "audio" || kind === "
|
|
989
|
+
if (kind === "video" || kind === "audio" || kind === "caption") return {
|
|
924
990
|
extent: "bounded",
|
|
925
991
|
sampling: "native"
|
|
926
992
|
};
|
|
@@ -961,7 +1027,7 @@ const generatedRelationSpec = Object.freeze({
|
|
|
961
1027
|
});
|
|
962
1028
|
const captionAlignmentRelationSpec = Object.freeze({
|
|
963
1029
|
kind: "caption-alignment",
|
|
964
|
-
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["caption"]), new Set(["audio"
|
|
1030
|
+
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["caption"]), new Set(["audio"])),
|
|
965
1031
|
validateMetadata: isCaptionAlignmentMetadata
|
|
966
1032
|
});
|
|
967
1033
|
/** `clip-anchor(child, host)` means endpoint 0 follows endpoint 1. */
|
|
@@ -970,20 +1036,29 @@ const clipAnchorRelationSpec = Object.freeze({
|
|
|
970
1036
|
validateEndpoints: (endpoints) => endpoints[0].current().entityKind === "clip" && endpoints[1].current().entityKind === "clip",
|
|
971
1037
|
validateMetadata: isEmptyMetadata
|
|
972
1038
|
});
|
|
973
|
-
/**
|
|
1039
|
+
/**
|
|
1040
|
+
* The rendered voiceover Audio and the PhoneticScript it was synthesized from;
|
|
1041
|
+
* kinds determine roles regardless of endpoint positions.
|
|
1042
|
+
*/
|
|
974
1043
|
const phoneticScriptRenderRelationSpec = Object.freeze({
|
|
975
1044
|
kind: "phonetic-script-render",
|
|
976
|
-
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["
|
|
1045
|
+
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["audio"]), new Set(["phonetic-script"])),
|
|
1046
|
+
validateMetadata: isEmptyMetadata
|
|
1047
|
+
});
|
|
1048
|
+
/**
|
|
1049
|
+
* The timbre identity a rendered voiceover Audio was synthesized with. Voice
|
|
1050
|
+
* stays an identity: it never carries the audio itself, so the link between the
|
|
1051
|
+
* two is a Relation rather than one shared entity.
|
|
1052
|
+
*/
|
|
1053
|
+
const voiceTimbreRelationSpec = Object.freeze({
|
|
1054
|
+
kind: "voice-timbre",
|
|
1055
|
+
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["audio"]), new Set(["voice"])),
|
|
977
1056
|
validateMetadata: isEmptyMetadata
|
|
978
1057
|
});
|
|
979
1058
|
/** AudioScript was transcribed from Audio, Video, or recorded Voice; kinds determine roles. */
|
|
980
1059
|
const audioScriptSourceRelationSpec = Object.freeze({
|
|
981
1060
|
kind: "audio-script-source",
|
|
982
|
-
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["audio-script"]), new Set([
|
|
983
|
-
"audio",
|
|
984
|
-
"video",
|
|
985
|
-
"voice"
|
|
986
|
-
])),
|
|
1061
|
+
validateEndpoints: (endpoints) => hasKinds(endpoints, new Set(["audio-script"]), new Set(["audio", "video"])),
|
|
987
1062
|
validateMetadata: isEmptyMetadata
|
|
988
1063
|
});
|
|
989
1064
|
/**
|
|
@@ -1010,6 +1085,7 @@ const builtInRelationSpecs = Object.freeze([
|
|
|
1010
1085
|
captionAlignmentRelationSpec,
|
|
1011
1086
|
clipAnchorRelationSpec,
|
|
1012
1087
|
phoneticScriptRenderRelationSpec,
|
|
1088
|
+
voiceTimbreRelationSpec,
|
|
1013
1089
|
audioScriptSourceRelationSpec,
|
|
1014
1090
|
audioScriptMarkerRelationSpec
|
|
1015
1091
|
]);
|
|
@@ -1039,7 +1115,7 @@ function hasAssetAndSequence(endpoints) {
|
|
|
1039
1115
|
return first.entityKind === "asset" && hasSequence(second) || second.entityKind === "asset" && hasSequence(first);
|
|
1040
1116
|
}
|
|
1041
1117
|
function isGeneratedMedia(entity) {
|
|
1042
|
-
return entity.entityKind === "video" || entity.entityKind === "image" || entity.entityKind === "audio"
|
|
1118
|
+
return entity.entityKind === "video" || entity.entityKind === "image" || entity.entityKind === "audio";
|
|
1043
1119
|
}
|
|
1044
1120
|
function isEmptyMetadata(value) {
|
|
1045
1121
|
return isJsonObject(value) && Object.keys(value).length === 0;
|
|
@@ -1788,7 +1864,7 @@ var EntitySandbox = class {
|
|
|
1788
1864
|
}
|
|
1789
1865
|
for (const row of rows.relations) {
|
|
1790
1866
|
if (this.state.relations.some((relation) => relation.relation_id === row.relationId)) continue;
|
|
1791
|
-
if (row.relationKind !== "timeline-track") throw new Error(`Unexpected resource Relation ${row.relationKind}`);
|
|
1867
|
+
if (row.relationKind !== "timeline-track" && row.relationKind !== "voice-timbre") throw new Error(`Unexpected resource Relation ${row.relationKind}`);
|
|
1792
1868
|
this.link({
|
|
1793
1869
|
relation_id: row.relationId,
|
|
1794
1870
|
relation_kind: row.relationKind,
|
|
@@ -2095,4 +2171,4 @@ const numericMarkerComparators = { compareMarkerPoints: (_marker, _range, left,
|
|
|
2095
2171
|
//#endregion
|
|
2096
2172
|
export { isJsonObject as a, isMediaAssetVariantKind as c, businessState as i, toDslRows as n, createEntityId as o, businessFacades as r, createRelationId as s, EntitySandbox as t };
|
|
2097
2173
|
|
|
2098
|
-
//# sourceMappingURL=entity-sandbox-
|
|
2174
|
+
//# sourceMappingURL=entity-sandbox-CzaUmSsS.mjs.map
|