@mengine/medeo-tool 1.4.1-alpha.3 → 1.4.1-alpha.5
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-DQ56Ihrh.d.mts → entity-contract-DlmUSouB.d.mts} +2 -2
- package/dist/{entity-sandbox-BH-7F5C8.mjs → entity-sandbox-TaUVT3on.mjs} +30 -43
- package/dist/entity-sandbox-TaUVT3on.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +43 -51
- package/dist/index.mjs.map +1 -1
- package/dist/sandbox-api.d.mts +1 -1
- package/dist/worker-entry.d.mts +1 -1
- package/dist/worker-entry.mjs +33 -17
- package/dist/worker-entry.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/entity-sandbox-BH-7F5C8.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;",
|
|
@@ -1038,15 +1038,15 @@ 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:[]. Locate
|
|
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
1050
|
|
|
1051
1051
|
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
1052
|
|
|
@@ -1802,13 +1802,10 @@ async function materializeResources(options, resources) {
|
|
|
1802
1802
|
ids.push(sandbox.entities.ensureMedia(resource).contentEntityId);
|
|
1803
1803
|
continue;
|
|
1804
1804
|
}
|
|
1805
|
-
const
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
const captions = sandbox.relations.of(assetId, "physical-asset").map((edge) => sandbox.entities.get(edge.endpoint_0_entity_id)).filter((entity) => entity?.entity_kind === "caption");
|
|
1810
|
-
if (captions.length !== 1) throw new Error("Caption resource must resolve to one materialized Caption");
|
|
1811
|
-
ids.push(captions[0].entity_id);
|
|
1805
|
+
const existingCaptions = sandbox.entities.list().filter((row) => row.entity_kind === "caption" && row.payload.external?.key === resource.assetId);
|
|
1806
|
+
if (existingCaptions.length) {
|
|
1807
|
+
if (existingCaptions.some((caption) => caption.payload.storageKey !== resource.storageKey)) throw new Error("Conflicting Caption resource identity");
|
|
1808
|
+
ids.push(...existingCaptions.map((caption) => caption.entity_id));
|
|
1812
1809
|
continue;
|
|
1813
1810
|
}
|
|
1814
1811
|
if (!resource.assetId.trim() || !resource.storageKey.trim() || !resource.segments.length) throw new Error("Caption resource requires a physical locator and timed segments");
|
|
@@ -1816,35 +1813,48 @@ async function materializeResources(options, resources) {
|
|
|
1816
1813
|
if (typeof segment.text !== "string" || !Number.isFinite(segment.startMs) || !Number.isFinite(segment.endMs) || segment.startMs < 0 || segment.endMs <= segment.startMs) throw new Error("Caption resource has invalid ASR text or timing");
|
|
1817
1814
|
for (const word of segment.words ?? []) if (typeof word.text !== "string" || !Number.isFinite(word.startMs) || !Number.isFinite(word.endMs) || word.startMs < segment.startMs || word.endMs > segment.endMs || word.endMs < word.startMs) throw new Error("Caption resource has invalid ASR word timing");
|
|
1818
1815
|
}
|
|
1819
|
-
const scriptId =
|
|
1820
|
-
if (!scriptId) throw new Error("Document AudioScript is not initialized");
|
|
1821
|
-
const script = sandbox.entities.get(scriptId);
|
|
1816
|
+
const scriptId = stableId("entity", "audio-script", resource.assetId);
|
|
1822
1817
|
const segments = resource.segments.map((segment, index) => ({
|
|
1823
1818
|
segmentId: stableId("segment", resource.assetId, String(index)),
|
|
1824
1819
|
text: segment.text
|
|
1825
1820
|
}));
|
|
1826
1821
|
const start = Math.min(...resource.segments.map((segment) => segment.startMs));
|
|
1827
1822
|
const end = Math.max(...resource.segments.map((segment) => segment.endMs));
|
|
1828
|
-
sandbox.entities.update({
|
|
1829
|
-
entity_id: scriptId,
|
|
1830
|
-
payload: { segments: [...script.payload.segments, ...segments] }
|
|
1831
|
-
});
|
|
1832
|
-
const captionId = stableId("entity", "caption", resource.assetId);
|
|
1833
1823
|
sandbox.entities.create({
|
|
1834
|
-
entity_id:
|
|
1835
|
-
entity_kind: "
|
|
1836
|
-
payload: {
|
|
1837
|
-
baseEntityIds: [scriptId],
|
|
1838
|
-
selections: segments.map(({ segmentId }) => ({ segmentId })),
|
|
1839
|
-
extent: {
|
|
1840
|
-
kind: "bounded",
|
|
1841
|
-
start,
|
|
1842
|
-
end
|
|
1843
|
-
},
|
|
1844
|
-
sampling: "native",
|
|
1845
|
-
coordinateSpace: "milliseconds"
|
|
1846
|
-
}
|
|
1824
|
+
entity_id: scriptId,
|
|
1825
|
+
entity_kind: "audio-script",
|
|
1826
|
+
payload: { segments }
|
|
1847
1827
|
});
|
|
1828
|
+
const ranges = resource.segments.map((segment, index) => ({
|
|
1829
|
+
segmentId: segments[index].segmentId,
|
|
1830
|
+
startMs: segment.startMs,
|
|
1831
|
+
endMs: segment.endMs
|
|
1832
|
+
}));
|
|
1833
|
+
for (const range of ranges) {
|
|
1834
|
+
const captionId = stableId("entity", "caption", resource.assetId, range.segmentId);
|
|
1835
|
+
sandbox.entities.create({
|
|
1836
|
+
entity_id: captionId,
|
|
1837
|
+
entity_kind: "caption",
|
|
1838
|
+
payload: {
|
|
1839
|
+
baseEntityIds: [scriptId],
|
|
1840
|
+
external: {
|
|
1841
|
+
system: "memota",
|
|
1842
|
+
key: resource.assetId
|
|
1843
|
+
},
|
|
1844
|
+
storageKey: resource.storageKey,
|
|
1845
|
+
selection: { segmentId: range.segmentId },
|
|
1846
|
+
segmentRanges: [range],
|
|
1847
|
+
extent: {
|
|
1848
|
+
kind: "bounded",
|
|
1849
|
+
start: range.startMs,
|
|
1850
|
+
end: range.endMs
|
|
1851
|
+
},
|
|
1852
|
+
sampling: "native",
|
|
1853
|
+
coordinateSpace: "milliseconds"
|
|
1854
|
+
}
|
|
1855
|
+
});
|
|
1856
|
+
ids.push(captionId);
|
|
1857
|
+
}
|
|
1848
1858
|
const markerId = sandbox.entities.create({
|
|
1849
1859
|
entity_id: stableId("entity", "asr-marker", resource.assetId),
|
|
1850
1860
|
entity_kind: "sequence-marker",
|
|
@@ -1871,24 +1881,6 @@ async function materializeResources(options, resources) {
|
|
|
1871
1881
|
endpoint_0_entity_id: scriptId,
|
|
1872
1882
|
endpoint_1_entity_id: markerId
|
|
1873
1883
|
});
|
|
1874
|
-
sandbox.entities.create({
|
|
1875
|
-
entity_id: assetId,
|
|
1876
|
-
entity_kind: "asset",
|
|
1877
|
-
payload: {
|
|
1878
|
-
external: {
|
|
1879
|
-
system: "memota",
|
|
1880
|
-
key: resource.assetId
|
|
1881
|
-
},
|
|
1882
|
-
storageKey: resource.storageKey
|
|
1883
|
-
}
|
|
1884
|
-
});
|
|
1885
|
-
sandbox.relations.link({
|
|
1886
|
-
relation_id: stableId("relation", captionId, assetId),
|
|
1887
|
-
relation_kind: "physical-asset",
|
|
1888
|
-
endpoint_0_entity_id: captionId,
|
|
1889
|
-
endpoint_1_entity_id: assetId
|
|
1890
|
-
});
|
|
1891
|
-
ids.push(captionId);
|
|
1892
1884
|
}
|
|
1893
1885
|
const candidate = sandbox.buildPlan();
|
|
1894
1886
|
if (candidate.commands.length && options.loadGenerationFacts) {
|