@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 CHANGED
@@ -84,6 +84,15 @@ Resource-free Caption composition from AudioScript is also supported. Each
84
84
  on-screen placement has its own Clip and display SequenceMarker, connected by
85
85
  ordinary relations; intrinsic Caption timing remains independent.
86
86
 
87
+ Voice resources use `external: {system: 'memota-speech', key: speechId}`.
88
+ Await `rgetAssetFromEntity(voiceId)` before constructing placement relations: the
89
+ host supplies `storageKey`, the full millisecond `extent`, and the optional TTS
90
+ `voice` locator. The loader returns `{assetId, content: {storageKey, durationMs,
91
+ voice?}}` from a project-scoped Speech lookup. Recorded speech omits `voice`;
92
+ TTS retains its explicit PhoneticScript relation. Resource reads do not create
93
+ script text or display markers. New or changed Speech references are also
94
+ resolved before commit, and failed reads publish no partial edits.
95
+
87
96
  `materializeResources` and generation/resource loaders are host APIs. The model
88
97
  never receives these capabilities. Project initialization and historical data
89
98
  migration also remain outside script execution. Retrying an unconfirmed commit
@@ -106,7 +106,7 @@ interface EntityPayloadByKind {
106
106
  };
107
107
  caption: BoundedNativeSequencePayload & {
108
108
  baseEntityIds: string[];
109
- selections: CaptionTextSelection[];
109
+ selection: CaptionTextSelection;
110
110
  style?: JsonObject;
111
111
  segmentRanges?: {
112
112
  segmentId: string;
@@ -116,7 +116,7 @@ interface EntityPayloadByKind {
116
116
  };
117
117
  }
118
118
  /** Stored own fields; a variant may obtain required content fields from its declared bases. */
119
- type StoredEntityPayload<K extends KnownEntityKind> = EntityPayloadByKind[K] | (K extends 'caption' ? JsonObject & Pick<MediaAssetPayload, 'external'> : never) | (JsonObject & Partial<EntityPayloadByKind[K]> & {
119
+ type StoredEntityPayload<K extends KnownEntityKind> = EntityPayloadByKind[K] | (K extends 'caption' | 'voice' ? JsonObject & Pick<MediaAssetPayload, 'external'> : never) | (JsonObject & Partial<EntityPayloadByKind[K]> & {
120
120
  baseEntityIds: string[];
121
121
  });
122
122
  interface SandboxEntity<K extends KnownEntityKind = KnownEntityKind> {
@@ -238,4 +238,4 @@ interface BusinessRelationFacade {
238
238
  }
239
239
  //#endregion
240
240
  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-DQ56Ihrh.d.mts.map
241
+ //# sourceMappingURL=entity-contract-G4HxwNXl.d.mts.map
@@ -209,15 +209,15 @@ function assembleCaptionContent(rows, captionEntityId) {
209
209
  requireEntityKind(rows, captionEntityId, "caption");
210
210
  const caption = assembleEntityContent(rows, captionEntityId);
211
211
  const script = findComposedAudioScript(rows, captionEntityId, "caption");
212
- const segments = selectAudioScriptSegments({
212
+ const segment = selectAudioScriptSegment({
213
213
  ...script,
214
214
  payload: caption.payload
215
- }, captionSelections(caption));
215
+ }, captionSelection(caption));
216
216
  return {
217
217
  caption,
218
218
  audioScript: script,
219
- segments,
220
- text: segments.map((segment) => segment.text).join("")
219
+ segments: [segment],
220
+ text: segment.text
221
221
  };
222
222
  }
223
223
  /**
@@ -239,20 +239,18 @@ function assemblePhoneticScriptContent(rows, phoneticScriptEntityId) {
239
239
  text: segments.map((segment) => segment.text).join("")
240
240
  };
241
241
  }
242
- function captionSelections(caption) {
243
- const selections = caption.payload.selections;
244
- if (!Array.isArray(selections) || selections.length === 0) throw new ScriptCompositionError("empty_selection", caption.entityId, `Caption "${caption.entityId}" requires a non-empty segment selection into its AudioScript`);
245
- if (!selections.every(isSegmentSelection)) throw new ScriptCompositionError("invalid_selection", caption.entityId, "Caption selections require a segmentId and optional textRange");
246
- return selections;
242
+ function captionSelection(caption) {
243
+ if (Object.hasOwn(caption.payload, "selections") || !isSegmentSelection(caption.payload.selection)) throw new ScriptCompositionError("invalid_selection", caption.entityId, "Caption requires one selection object with segmentId and optional textRange; selections arrays are forbidden");
244
+ return caption.payload.selection;
247
245
  }
248
246
  function isSegmentSelection(value) {
249
247
  return typeof value === "object" && value != null && !Array.isArray(value) && typeof value.segmentId === "string" && value.segmentId.trim() !== "" && Object.keys(value).every((key) => key === "segmentId" || key === "textRange");
250
248
  }
251
249
  /** Select source text without creating another authoritative text field. */
252
- function selectAudioScriptSegments(script, selections) {
253
- if (!Array.isArray(selections) || selections.length === 0 || !selections.every(isSegmentSelection) || new Set(selections.map((s) => s.segmentId)).size !== selections.length) throw new ScriptCompositionError("invalid_selection", script.entityId, "Caption selections must be non-empty and name unique source segments");
250
+ function selectAudioScriptSegment(script, selection) {
251
+ if (!isSegmentSelection(selection)) throw new ScriptCompositionError("invalid_selection", script.entityId, "Caption requires one selection object with segmentId and optional textRange");
254
252
  const bySegmentId = new Map(scriptSegments(script).map((segment) => [segment.segmentId, segment]));
255
- const selected = selections.map((selection) => {
253
+ const selected = (() => {
256
254
  const segment = bySegmentId.get(selection.segmentId);
257
255
  if (segment === void 0) throw new ScriptCompositionError("unknown_segment", script.entityId, `Caption selection "${selection.segmentId}" does not name a segment of AudioScript "${script.entityId}"`);
258
256
  if (selection.textRange === void 0) return segment;
@@ -263,8 +261,8 @@ function selectAudioScriptSegments(script, selections) {
263
261
  ...segment,
264
262
  text: points.slice(range.start, range.end).join("")
265
263
  };
266
- });
267
- if (!selected.map((segment) => segment.text).join("").trim()) throw new ScriptCompositionError("empty_selection", script.entityId, "Caption selection must contain visible source text");
264
+ })();
265
+ if (!selected.text.trim()) throw new ScriptCompositionError("empty_selection", script.entityId, "Caption selection must contain visible source text");
268
266
  return selected;
269
267
  }
270
268
  function requireEntityKind(rows, entityIdValue, entityKind) {
@@ -736,25 +734,15 @@ function validateVoicePayload(value, problems) {
736
734
  function validateCaptionPayload(value, problems) {
737
735
  validateExternalLocator(value, problems);
738
736
  if (value.segmentRanges !== void 0) validateSegmentRanges(value.segmentRanges, problems);
739
- const selections = value.selections;
740
- if (!Array.isArray(selections)) problems.push("selections must be a non-empty array of AudioScript segment selections");
737
+ if (Object.hasOwn(value, "selections")) problems.push("selections is forbidden; Caption requires one selection object");
738
+ const selection = value.selection;
739
+ if (!isRecord(selection)) problems.push("selection must be one AudioScript segment selection object, not an array");
741
740
  else {
742
- if (selections.length === 0) problems.push("selections must name at least one AudioScript segment");
743
- const seen = /* @__PURE__ */ new Set();
744
- for (const [index, selection] of selections.entries()) {
745
- if (!isRecord(selection)) {
746
- problems.push(`selections[${index}] must be an object`);
747
- continue;
748
- }
749
- if (typeof selection.segmentId !== "string" || selection.segmentId.trim() === "") problems.push(`selections[${index}].segmentId must be a string`);
750
- else if (seen.has(selection.segmentId)) problems.push(`selections[${index}].segmentId must be unique within the Caption`);
751
- else seen.add(selection.segmentId);
752
- if (Object.keys(selection).some((key) => key !== "segmentId" && key !== "textRange")) problems.push(`selections[${index}] may only contain segmentId and textRange`);
753
- if (selection.textRange !== void 0) {
754
- const range = selection.textRange;
755
- if (!isRecord(range) || !Number.isSafeInteger(range.start) || !Number.isSafeInteger(range.end) || range.start < 0 || range.end <= range.start || Object.keys(range).some((key) => key !== "start" && key !== "end")) problems.push(`selections[${index}].textRange must be a non-empty half-open code-point range`);
756
- }
757
- }
741
+ if (typeof selection.segmentId !== "string" || !selection.segmentId.trim()) problems.push("selection.segmentId must be a non-empty string");
742
+ if (Object.keys(selection).some((key) => key !== "segmentId" && key !== "textRange")) problems.push("selection may only contain segmentId and textRange");
743
+ const range = selection.textRange;
744
+ if (range !== void 0 && (!isRecord(range) || !Number.isSafeInteger(range.start) || !Number.isSafeInteger(range.end) || range.start < 0 || range.end <= range.start || Object.keys(range).some((key) => key !== "start" && key !== "end"))) problems.push("selection.textRange must be a non-empty half-open code-point range");
745
+ if (Array.isArray(value.segmentRanges) && (value.segmentRanges.length !== 1 || !isRecord(value.segmentRanges[0]) || value.segmentRanges[0].segmentId !== selection.segmentId)) problems.push("Caption segmentRanges must contain only the selected segment timing");
758
746
  }
759
747
  const style = value.style;
760
748
  if (style === void 0) return;
@@ -878,7 +866,7 @@ function isOwnedLocalEntityValuePath(entityKind, path) {
878
866
  if (entityKind === "asset" && /^(?:external\.(?:system|key)|storageKey)$/.test(path)) return true;
879
867
  if (isMediaAssetVariantKind(entityKind) && /^(?:external\.(?:system|key)|storageKey)$/.test(path)) return true;
880
868
  if (entityKind === "voice" && /^voice\.(?:system|key|name)$/.test(path)) return true;
881
- if (entityKind === "caption" && (path.startsWith("style.") || /^selections\[\d+\]\.segmentId$/.test(path))) return true;
869
+ if (entityKind === "caption" && (path.startsWith("style.") || path === "selection.segmentId")) return true;
882
870
  if ([
883
871
  "audio-script",
884
872
  "caption",
@@ -893,7 +881,7 @@ function isOwnedLocalIdPath(entityKind, path) {
893
881
  "caption",
894
882
  "phonetic-script"
895
883
  ].includes(entityKind) && /^segments\[\d+\]\.segmentId$/.test(path)) return true;
896
- if (entityKind === "caption" && /^selections\[\d+\]\.segmentId$/.test(path)) return true;
884
+ if (entityKind === "caption" && path === "selection.segmentId") return true;
897
885
  if ((entityKind === "sequence-marker" || entityKind === "caption") && /^segmentRanges\[\d+\]\.segmentId$/.test(path)) return true;
898
886
  if (entityKind === "asset" && /^(?:tracks\[\d+\]\.trackId|renditions\[\d+\]\.renditionId)$/.test(path)) return true;
899
887
  return false;
@@ -2096,6 +2084,6 @@ const numericMarkerComparators = { compareMarkerPoints: (_marker, _range, left,
2096
2084
  return left - right;
2097
2085
  } };
2098
2086
  //#endregion
2099
- export { createEntityId as a, businessState as i, toDslRows as n, createRelationId as o, businessFacades as r, isMediaAssetVariantKind as s, EntitySandbox as t };
2087
+ 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 };
2100
2088
 
2101
- //# sourceMappingURL=entity-sandbox-OArq9NSH.mjs.map
2089
+ //# sourceMappingURL=entity-sandbox-TaUVT3on.mjs.map