@mengine/medeo-tool 1.4.1-alpha.4 → 2.0.1-alpha.2
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 +9 -0
- package/dist/{entity-contract-DQ56Ihrh.d.mts → entity-contract-G4HxwNXl.d.mts} +3 -3
- package/dist/{entity-sandbox-OArq9NSH.mjs → entity-sandbox-TaUVT3on.mjs} +24 -36
- package/dist/entity-sandbox-TaUVT3on.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +38 -34
- package/dist/index.mjs.map +1 -1
- package/dist/sandbox-api.d.mts +3 -3
- package/dist/worker-entry.d.mts +1 -1
- package/dist/worker-entry.mjs +77 -13
- package/dist/worker-entry.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/entity-sandbox-OArq9NSH.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as isMediaAssetVariantKind, i as businessState, o as createEntityId, s as createRelationId, t as EntitySandbox } from "./entity-sandbox-TaUVT3on.mjs";
|
|
2
2
|
import { LoroEntityDocument, ManualSyncDoc, MengineHttpClient, MengineHttpRequestError, ValidationError, base64ToBytes, bytesToBase64, compileEntityRows, createMirrorVideoDocument, createPlainMemoryAdapter, decodeDocVersionMark, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, replayJournal, solveVideoDocument, speedOf, toVideoDocument } from "@mengine/medeo-client";
|
|
3
3
|
import { Worker } from "node:worker_threads";
|
|
4
4
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -854,7 +854,7 @@ const ENTITY_EDIT_SANDBOX_API_DTS = [
|
|
|
854
854
|
" };",
|
|
855
855
|
" caption: BoundedNativeSequencePayload & {",
|
|
856
856
|
" baseEntityIds: string[];",
|
|
857
|
-
"
|
|
857
|
+
" selection: CaptionTextSelection;",
|
|
858
858
|
" style?: JsonObject;",
|
|
859
859
|
" segmentRanges?: {",
|
|
860
860
|
" segmentId: string;",
|
|
@@ -985,7 +985,7 @@ const ENTITY_EDIT_SANDBOX_API_DTS = [
|
|
|
985
985
|
"/** Stored own fields; a variant may obtain required content fields from its declared bases. */",
|
|
986
986
|
"export type StoredEntityPayload<K extends KnownEntityKind> =",
|
|
987
987
|
" | EntityPayloadByKind[K]",
|
|
988
|
-
" | (K extends 'caption' ? JsonObject & Pick<MediaAssetPayload, 'external'> : never)",
|
|
988
|
+
" | (K extends 'caption' | 'voice' ? JsonObject & Pick<MediaAssetPayload, 'external'> : never)",
|
|
989
989
|
" | (JsonObject &",
|
|
990
990
|
" Partial<EntityPayloadByKind[K]> & {",
|
|
991
991
|
" baseEntityIds: string[];",
|
|
@@ -1008,7 +1008,7 @@ const ENTITY_EDIT_SANDBOX_API_DTS = [
|
|
|
1008
1008
|
"}",
|
|
1009
1009
|
"export declare const entities: BusinessEntityFacade;",
|
|
1010
1010
|
"export declare const relations: BusinessRelationFacade;",
|
|
1011
|
-
"/** Resolve this Entity's attached resource through the host; await before using an uninitialized Caption. */",
|
|
1011
|
+
"/** Resolve this Entity's attached resource through the host; await before using an uninitialized Caption or Voice. */",
|
|
1012
1012
|
"export declare function rgetAssetFromEntity(entityId: string): Promise<EntityAssetContent>;",
|
|
1013
1013
|
"export declare function checkpoint(): EntitySandboxCheckpoint;",
|
|
1014
1014
|
"export declare function rollbackTo(cp: EntitySandboxCheckpoint): void;",
|
|
@@ -1038,15 +1038,17 @@ The host supplies the current document. Do not invent or request a document id.
|
|
|
1038
1038
|
|
|
1039
1039
|
Entity reads return assembled snapshots. Mutating returned objects has no persistence effect. Create declares own fields. Update requires a nonempty changes array and atomically applies its ordered operations to assembled fields, routing each to its declaring owner. DeclareFields explicitly establishes own fields or an override; it is not the normal way to edit inherited content. Deletion requires explicitly handling incident relations, variant references and protected project attachments; it never deletes external resources or cascades business entities.
|
|
1040
1040
|
|
|
1041
|
-
FieldChange paths start at payload for an entity, and at metadata or trace for a relation. Use strings for fields and {elementId:'...'} for list members, never numeric indices. Segment identity is segmentId; reference identity is the referenced id. set writes scalars or schema-declared atomic values, including complete sourceRange, targetRange, extent, duration, timeRemapping, textRange and external. It cannot replace collaborative text, lists or maps. Edit text with text.splice (Unicode code-point index and deleteCount), and segments/
|
|
1041
|
+
FieldChange paths start at payload for an entity, and at metadata or trace for a relation. Use strings for fields and {elementId:'...'} for list members, never numeric indices. Segment identity is segmentId; reference identity is the referenced id. set writes scalars or schema-declared atomic values, including complete sourceRange, targetRange, extent, duration, timeRemapping, selection, textRange and external. It cannot replace collaborative text, lists or maps. Edit text with text.splice (Unicode code-point index and deleteCount), and segments/segmentRanges with list.insert, list.move or list.remove. beforeElementId:null means append; moving before itself, duplicate identity or an absent anchor is an error. Unset removes optional fields only. Map fields are edited through leaf paths; initialize a new own map via declareFields. baseEntityIds is unordered composition membership: insert/remove are supported, moving bases cannot resolve field conflicts. Independent fields and list-item text edits retain native Loro identities.
|
|
1042
1042
|
|
|
1043
1043
|
Entities own data. Relations associate two existing entities; endpoint_0 and endpoint_1 retain their declared positions. Each relation kind defines direction and meaning; neither relation listing order nor endpoint storage order implies a global business order. Relations.update changes metadata/trace fields only; kind/endpoints require explicit unlink plus link with a new identity. Generated relations use generated(output,input). Ordinary associations do not implement composition.
|
|
1044
1044
|
|
|
1045
1045
|
Variants directly hold baseEntityIds. Assembly validates every base before applying explicit own overrides: two bases supplying the same field are an error even if values match or the variant declares that field. Missing/cyclic bases fail. Consumers operate assembled fields without copying inherited content or resolving owners themselves. An owned-field edit creates a new immutable entity version. Base changes automatically advance variant base references and project attachments without versioning an unchanged variant. A variant-owned change versions the variant and retains unchanged bases. Do not manually clone entities for versioning. Use the current plan's ids throughout that execution; refresh after commit.
|
|
1046
1046
|
|
|
1047
|
-
Generation tools return resource references. An asset id may be passed in an entity's external:{system:'memota',key:assetId}; it is never an entity id, baseEntityId or relation endpoint. Physical resources are host infrastructure. The sandbox has no direct resource lookup/CRUD by asset id. rgetAssetFromEntity takes only an existing business entity id and returns {assetId,content} for its attached resource. For output_caption, create a Caption with payload:{external:{system:'memota',key:assetId}}, then await rgetAssetFromEntity(captionId). The host initializes
|
|
1047
|
+
Generation tools return resource references. An asset id may be passed in an entity's external:{system:'memota',key:assetId}; it is never an entity id, baseEntityId or relation endpoint. Physical resources are host infrastructure. The sandbox has no direct resource lookup/CRUD by asset id. rgetAssetFromEntity takes only an existing business entity id and returns {assetId,content} for its attached resource. For output_caption, create a Caption with payload:{external:{system:'memota',key:assetId}}, then await rgetAssetFromEntity(captionId). The host initializes the complete AudioScript and one Caption per resource segment in the same causal plan when selection is omitted. The requested Caption represents the first segment; additional Caption entities share that same script and external reference. After awaiting, discover ALL resource Captions with entities.list filtered by entity_kind and payload.external.key, inspect each singular selection/extent, and place each in its own Clip/SequenceMarker. An explicit selection initializes only that selected Caption. Never place the first Caption over the whole transcript; Without explicit bases, the host creates an independent AudioScript for that resource. With bases, it resolves their unique AudioScript text owner and preserves other nonconflicting bases. It never routes text through the panel selection. Read the editable fields with entities.get afterwards. Repeated reads preserve edited text and return the original immutable resource content. Unawaited initialization is completed before validation; failure prevents publication. Resource-free Caption composition from AudioScript is also valid.
|
|
1048
1048
|
|
|
1049
|
-
Project initialization creates one current Timeline, the four standard Tracks and one attached AudioScript with segments:[]. A project may contain multiple independent complete AudioScripts (for example a generated script and an uploaded video transcript). The project AudioScript attachment selects only the panel view; it is not a singleton or membership constraint. Locate scripts with entities.list and choose the appropriate source. AudioScript owns independent multi-segment text; each can have multiple Caption variants. Caption and PhoneticScript compose it through baseEntityIds. Caption owns
|
|
1049
|
+
Project initialization creates one current Timeline, the four standard Tracks and one attached AudioScript with segments:[]. A project may contain multiple independent complete AudioScripts (for example a generated script and an uploaded video transcript). The project AudioScript attachment selects only the panel view; it is not a singleton or membership constraint. Locate scripts with entities.list and choose the appropriate source. AudioScript owns independent multi-segment text; each can have multiple Caption variants. Caption and PhoneticScript compose it through baseEntityIds. Caption owns exactly one selection object ({segmentId,textRange?}), never an array or the legacy selections field. It selects one script segment or a contiguous substring, and owns only that selection's intrinsic timing and style; segmentId is a stable script-local identity, not an entity reference or transient array index; selection textRange is a half-open code-point range and can split display text without rewriting the script. PhoneticScript owns pronunciation/prosody; Voice is generated from it and related by phonetic-script-render(voice,phoneticScript). Speech and caption occupy separate Clips. Subtitles normally accompany sound; use source media or generate Voice from PhoneticScript when the request requires narration. Do not fabricate a sound resource.
|
|
1050
|
+
|
|
1051
|
+
For Speech resources, create a Voice with external:{system:'memota-speech',key:speechId}, then await rgetAssetFromEntity(voiceId) before linking its placement. The host supplies full extent and optional voice-library identity, and assembles physical storage facts internally. Read the visible fields through entities.get; never invent them or use a Speech ID as a Memota media ID. TTS Voice still requires its real PhoneticScript relation; resource loading does not invent script content.
|
|
1050
1052
|
|
|
1051
1053
|
AudioScript has no intrinsic time and cannot be Clip content. ASR input Audio/Video/Voice associates via audio-script-source(script,source). Its external annotation SequenceMarker associates via audio-script-marker(script,marker) and receives assigned segmentRanges, not references to another marker. Caption intrinsic timing and its Clip's display SequenceMarker are distinct. Move/stretch display by editing only the placement marker.
|
|
1052
1054
|
|
|
@@ -1802,10 +1804,10 @@ async function materializeResources(options, resources) {
|
|
|
1802
1804
|
ids.push(sandbox.entities.ensureMedia(resource).contentEntityId);
|
|
1803
1805
|
continue;
|
|
1804
1806
|
}
|
|
1805
|
-
const
|
|
1806
|
-
if (
|
|
1807
|
-
if (
|
|
1808
|
-
ids.push(
|
|
1807
|
+
const existingCaptions = sandbox.entities.list().filter((row) => row.entity_kind === "caption" && row.payload.external?.key === resource.assetId);
|
|
1808
|
+
if (existingCaptions.length) {
|
|
1809
|
+
if (existingCaptions.some((caption) => caption.payload.storageKey !== resource.storageKey)) throw new Error("Conflicting Caption resource identity");
|
|
1810
|
+
ids.push(...existingCaptions.map((caption) => caption.entity_id));
|
|
1809
1811
|
continue;
|
|
1810
1812
|
}
|
|
1811
1813
|
if (!resource.assetId.trim() || !resource.storageKey.trim() || !resource.segments.length) throw new Error("Caption resource requires a physical locator and timed segments");
|
|
@@ -1830,28 +1832,31 @@ async function materializeResources(options, resources) {
|
|
|
1830
1832
|
startMs: segment.startMs,
|
|
1831
1833
|
endMs: segment.endMs
|
|
1832
1834
|
}));
|
|
1833
|
-
const
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1835
|
+
for (const range of ranges) {
|
|
1836
|
+
const captionId = stableId("entity", "caption", resource.assetId, range.segmentId);
|
|
1837
|
+
sandbox.entities.create({
|
|
1838
|
+
entity_id: captionId,
|
|
1839
|
+
entity_kind: "caption",
|
|
1840
|
+
payload: {
|
|
1841
|
+
baseEntityIds: [scriptId],
|
|
1842
|
+
external: {
|
|
1843
|
+
system: "memota",
|
|
1844
|
+
key: resource.assetId
|
|
1845
|
+
},
|
|
1846
|
+
storageKey: resource.storageKey,
|
|
1847
|
+
selection: { segmentId: range.segmentId },
|
|
1848
|
+
segmentRanges: [range],
|
|
1849
|
+
extent: {
|
|
1850
|
+
kind: "bounded",
|
|
1851
|
+
start: range.startMs,
|
|
1852
|
+
end: range.endMs
|
|
1853
|
+
},
|
|
1854
|
+
sampling: "native",
|
|
1855
|
+
coordinateSpace: "milliseconds"
|
|
1856
|
+
}
|
|
1857
|
+
});
|
|
1858
|
+
ids.push(captionId);
|
|
1859
|
+
}
|
|
1855
1860
|
const markerId = sandbox.entities.create({
|
|
1856
1861
|
entity_id: stableId("entity", "asr-marker", resource.assetId),
|
|
1857
1862
|
entity_kind: "sequence-marker",
|
|
@@ -1878,7 +1883,6 @@ async function materializeResources(options, resources) {
|
|
|
1878
1883
|
endpoint_0_entity_id: scriptId,
|
|
1879
1884
|
endpoint_1_entity_id: markerId
|
|
1880
1885
|
});
|
|
1881
|
-
ids.push(captionId);
|
|
1882
1886
|
}
|
|
1883
1887
|
const candidate = sandbox.buildPlan();
|
|
1884
1888
|
if (candidate.commands.length && options.loadGenerationFacts) {
|