@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.
@@ -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;
@@ -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-DlmUSouB.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;
@@ -1512,10 +1500,14 @@ var EntitySandbox = class {
1512
1500
  }
1513
1501
  /** Host-owned fixed structure is journaled through the same CAS graph as model edits. */
1514
1502
  ensureFoundation(timelinePayload = {}) {
1515
- const foundation = ensureEditorFoundation(toDslRows(this.state), this.idFactory, timelinePayload);
1503
+ const foundation = ensureEditorFoundation(toDslRows(this.state), this.idFactory, timelinePayload, this.state.audioScriptEntityId);
1516
1504
  this.appendResourceRows(foundation.rows);
1517
1505
  if (this.state.audioScriptEntityId === null) this.state.audioScriptEntityId = foundation.audioScriptEntityId;
1518
1506
  }
1507
+ /** Host assembly resolves the text owner before a resource Caption is complete. */
1508
+ captionAudioScriptId(entityId) {
1509
+ return findComposedAudioScript(toDslRows(this.state), createEntityId(entityId), "caption").entityId;
1510
+ }
1519
1511
  get audioScriptEntityId() {
1520
1512
  return this.state.audioScriptEntityId;
1521
1513
  }
@@ -1694,10 +1686,6 @@ var EntitySandbox = class {
1694
1686
  }
1695
1687
  const entityId = input.entity_id ?? this.idFactory("entity");
1696
1688
  assertTrimmed(entityId, "entity_id");
1697
- if (input.entity_kind === "audio-script") {
1698
- const existing = this.state.entities.find((entity) => entity.entity_kind === "audio-script");
1699
- if (existing !== void 0 && existing.entity_id !== entityId) throw new Error(`Editor requires exactly one AudioScript; edit ${existing.entity_id} instead of creating ${entityId}`);
1700
- }
1701
1689
  const entity = {
1702
1690
  entity_id: entityId,
1703
1691
  entity_kind: input.entity_kind,
@@ -1945,7 +1933,6 @@ var EntitySandbox = class {
1945
1933
  apply(command, enforceIdentity) {
1946
1934
  switch (command.kind) {
1947
1935
  case "create-entity": {
1948
- if (command.entity.entity_kind === "audio-script" && this.state.entities.some((entity) => entity.entity_kind === "audio-script")) throw new Error("The project AudioScript already exists; edit its segments instead");
1949
1936
  if (enforceIdentity && this.state.entities.some((entity) => entity.entity_id === command.entity.entity_id)) throw new Error(`Entity id "${command.entity.entity_id}" already exists`);
1950
1937
  const original = this.original.entities.find((entity) => entity.entity_id === command.entity.entity_id);
1951
1938
  if (enforceIdentity && original != null) throw new Error(`Entity id "${command.entity.entity_id}" was originally kind "${original.entity_kind}" and cannot be recreated as "${command.entity.entity_kind}"`);
@@ -2021,7 +2008,7 @@ var EntitySandbox = class {
2021
2008
  }
2022
2009
  case "delete-entity": {
2023
2010
  const target = this.state.entities.find((entity) => entity.entity_id === command.entity_id);
2024
- if (target && ["audio-script", "timeline"].includes(target.entity_kind)) throw new Error("The document AudioScript is a fixed project identity and cannot be deleted");
2011
+ if (target && (target.entity_kind === "timeline" || target.entity_id === this.state.audioScriptEntityId)) throw new Error("An entity attached to the project editor cannot be deleted");
2025
2012
  const dependents = this.state.entities.filter((entity) => Array.isArray(entity.payload.baseEntityIds) && entity.payload.baseEntityIds.includes(command.entity_id));
2026
2013
  if (dependents.length) throw new Error(`Entity ${command.entity_id} is still referenced by variants: ${dependents.map((row) => row.entity_id).join(", ")}`);
2027
2014
  const index = this.state.entities.findIndex((entity) => entity.entity_id === command.entity_id);
@@ -2097,6 +2084,6 @@ const numericMarkerComparators = { compareMarkerPoints: (_marker, _range, left,
2097
2084
  return left - right;
2098
2085
  } };
2099
2086
  //#endregion
2100
- 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 };
2101
2088
 
2102
- //# sourceMappingURL=entity-sandbox-BH-7F5C8.mjs.map
2089
+ //# sourceMappingURL=entity-sandbox-TaUVT3on.mjs.map