@mengine/medeo-tool 1.4.1-alpha.4 → 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/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as createEntityId, i as businessState, o as createRelationId, s as isMediaAssetVariantKind, t as EntitySandbox } from "./entity-sandbox-OArq9NSH.mjs";
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
- " selections: CaptionTextSelection[];",
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/selections/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.
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 Caption intrinsic timing and its composed AudioScript text in the same causal plan; 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.
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 selections ({segmentId,textRange?}), intrinsic segmentRanges 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.
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,10 +1802,10 @@ async function materializeResources(options, resources) {
1802
1802
  ids.push(sandbox.entities.ensureMedia(resource).contentEntityId);
1803
1803
  continue;
1804
1804
  }
1805
- const existingCaption = sandbox.entities.list().find((row) => row.entity_kind === "caption" && row.payload.external?.key === resource.assetId);
1806
- if (existingCaption) {
1807
- if (existingCaption.payload.storageKey !== resource.storageKey) throw new Error("Conflicting Caption resource identity");
1808
- ids.push(existingCaption.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));
1809
1809
  continue;
1810
1810
  }
1811
1811
  if (!resource.assetId.trim() || !resource.storageKey.trim() || !resource.segments.length) throw new Error("Caption resource requires a physical locator and timed segments");
@@ -1830,28 +1830,31 @@ async function materializeResources(options, resources) {
1830
1830
  startMs: segment.startMs,
1831
1831
  endMs: segment.endMs
1832
1832
  }));
1833
- const captionId = stableId("entity", "caption", resource.assetId);
1834
- sandbox.entities.create({
1835
- entity_id: captionId,
1836
- entity_kind: "caption",
1837
- payload: {
1838
- baseEntityIds: [scriptId],
1839
- external: {
1840
- system: "memota",
1841
- key: resource.assetId
1842
- },
1843
- storageKey: resource.storageKey,
1844
- segmentRanges: ranges,
1845
- selections: segments.map(({ segmentId }) => ({ segmentId })),
1846
- extent: {
1847
- kind: "bounded",
1848
- start,
1849
- end
1850
- },
1851
- sampling: "native",
1852
- coordinateSpace: "milliseconds"
1853
- }
1854
- });
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
+ }
1855
1858
  const markerId = sandbox.entities.create({
1856
1859
  entity_id: stableId("entity", "asr-marker", resource.assetId),
1857
1860
  entity_kind: "sequence-marker",
@@ -1878,7 +1881,6 @@ async function materializeResources(options, resources) {
1878
1881
  endpoint_0_entity_id: scriptId,
1879
1882
  endpoint_1_entity_id: markerId
1880
1883
  });
1881
- ids.push(captionId);
1882
1884
  }
1883
1885
  const candidate = sandbox.buildPlan();
1884
1886
  if (candidate.commands.length && options.loadGenerationFacts) {