@mengine/medeo-tool 1.3.1-alpha.6 → 1.3.1-alpha.9

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.
@@ -139,6 +139,8 @@ interface SandboxRelation {
139
139
  }
140
140
  interface EntityStoreSnapshot {
141
141
  revision: number;
142
+ /** Fixed identity outlet of the project's one AudioScript; null only before initialization (revision 0). */
143
+ audioScriptEntityId: string | null;
142
144
  entities: SandboxEntity[];
143
145
  relations: SandboxRelation[];
144
146
  }
@@ -269,4 +271,4 @@ interface RelationFacade {
269
271
  }
270
272
  //#endregion
271
273
  export { SandboxEntity as _, EntityFacade as a, UpdateEntityInput as b, JsonObject as c, KnownEntityKind as d, KnownRelationKind as f, ResourceEntityKind as g, RelationFacade as h, EntityCommand as i, JsonPrimitive as l, LinkRelationInput as m, CreateEntityInput as n, EntityPlanState as o, LinkGeneratedRelationInput as p, DeleteEntityInput as r, EntityStoreSnapshot as s, AuthorableRelationKind as t, JsonValue as u, SandboxRelation as v, UnlinkRelationInput as y };
272
- //# sourceMappingURL=entity-contract-hKZbJSRP.d.mts.map
274
+ //# sourceMappingURL=entity-contract-SQdOaLm-.d.mts.map
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as SandboxEntity, a as EntityFacade, b as UpdateEntityInput, c as JsonObject, d as KnownEntityKind, f as KnownRelationKind, g as ResourceEntityKind, h as RelationFacade, i as EntityCommand, l as JsonPrimitive, m as LinkRelationInput, n as CreateEntityInput, o as EntityPlanState, p as LinkGeneratedRelationInput, r as DeleteEntityInput, s as EntityStoreSnapshot, t as AuthorableRelationKind, u as JsonValue, v as SandboxRelation, y as UnlinkRelationInput } from "./entity-contract-hKZbJSRP.mjs";
1
+ import { _ as SandboxEntity, a as EntityFacade, b as UpdateEntityInput, c as JsonObject, d as KnownEntityKind, f as KnownRelationKind, g as ResourceEntityKind, h as RelationFacade, i as EntityCommand, l as JsonPrimitive, m as LinkRelationInput, n as CreateEntityInput, o as EntityPlanState, p as LinkGeneratedRelationInput, r as DeleteEntityInput, s as EntityStoreSnapshot, t as AuthorableRelationKind, u as JsonValue, v as SandboxRelation, y as UnlinkRelationInput } from "./entity-contract-SQdOaLm-.mjs";
2
2
  import { JournalEntry, ManualSyncDoc, MediaAssetFact, PartIdFactory, SemanticOpName, VideoDocument, VideoDraft, fromVideoDocument } from "@mengine/medeo-client";
3
3
  import { AddSpeechesInput, AddVideoClipsInput, AdjustBgmVolumeInput, AdjustSpeechVolumeInput, AdjustVideoClipDurationInput, AdjustVideoClipVolumeInput, ChangeSpeechScriptInput, ChangeSpeechVoiceInput, DeleteBgmInput, DeleteSpeechesInput, DeleteVideoClipsInput, MoveSpeechesInput, MoveVideoClipsByAnchorInput, MoveVideoClipsInput, ReplaceVideoClipContentInput, ReplaceVideoClipSequenceInput, SetBgmInput, SetCaptionStyleInput, SetCaptionVisibilityInput, SetVideoClipSpeedShiftInput } from "@mengine/medeo-client/schemas";
4
4
 
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { c as renderPreview, l as renderCompactProjection, n as EntitySandbox, o as isMediaAssetVariantKind, r as toDslRows, s as collectAffectedPartIds, t as EditSandboxSession } from "./script-session-1eqBGegp.mjs";
1
+ import { c as renderPreview, l as renderCompactProjection, n as EntitySandbox, o as isMediaAssetVariantKind, r as toDslRows, s as collectAffectedPartIds, t as EditSandboxSession } from "./script-session-B2UQ1W_y.mjs";
2
2
  import { EntityGraphHttpClient, ManualSyncDoc, MengineHttpClient, MengineHttpRequestError, ValidationError, createMirrorVideoDocument, createPlainMemoryAdapter, decodeDocVersionMark, encodeDocVersionMark, migrateLegacyTimelineToEntities, replayJournal, toVideoDocument } from "@mengine/medeo-client";
3
3
  import { Worker } from "node:worker_threads";
4
4
  import { randomUUID } from "node:crypto";
@@ -279,9 +279,14 @@ function toSnapshot(value, expectedDocId) {
279
279
  if (!isRecord$2(value) || typeof value.doc_id !== "string" || !isNonNegativeInteger(value.revision)) throw new Error("invalid entity-state response envelope");
280
280
  if (value.doc_id !== expectedDocId) throw new Error(`entity-state response doc_id mismatch: expected "${expectedDocId}"`);
281
281
  if (!isRecord$2(value.rows) || !Array.isArray(value.rows.entities) || !Array.isArray(value.rows.relations)) throw new Error("invalid entity-state response rows");
282
+ if (value.audio_script_entity_id === null) {
283
+ if (value.revision !== 0) throw new Error("Document AudioScript is not initialized");
284
+ } else if (!isTrimmed(value.audio_script_entity_id)) throw new Error("invalid document AudioScript identity");
282
285
  const response = value;
286
+ if (response.audio_script_entity_id !== null && !response.rows.entities.some((entity) => entity.entity_id === response.audio_script_entity_id && entity.entity_kind === "audio-script")) throw new Error("Document AudioScript must name the project AudioScript");
283
287
  return {
284
288
  revision: response.revision,
289
+ audioScriptEntityId: response.audio_script_entity_id,
285
290
  entities: response.rows.entities.map(parseEntity),
286
291
  relations: response.rows.relations.map(parseRelation)
287
292
  };
@@ -790,6 +795,8 @@ const ENTITY_EDIT_SANDBOX_API_DTS = [
790
795
  "}",
791
796
  "export interface EntityStoreSnapshot {",
792
797
  " revision: number;",
798
+ " /** Fixed identity outlet of the project's one AudioScript; null only before initialization (revision 0). */",
799
+ " audioScriptEntityId: string | null;",
793
800
  " entities: SandboxEntity[];",
794
801
  " relations: SandboxRelation[];",
795
802
  "}",
@@ -1219,7 +1226,9 @@ const ENTITY_EDIT_SANDBOX_API_DTS = [
1219
1226
  " insertCaptionClip(input: InsertCaptionClipInput): ClipEntityId;",
1220
1227
  "}",
1221
1228
  "export interface TimelineApi {",
1222
- " snapshot(): EntityStoreSnapshot;",
1229
+ " snapshot(): EntityStoreSnapshot & {",
1230
+ " audioScriptEntityId: string;",
1231
+ " };",
1223
1232
  "}",
1224
1233
  "export interface SandboxCheckpoint {",
1225
1234
  " readonly index: number;",
@@ -1259,7 +1268,7 @@ The compatibility reader supports the existing four Track roles: video_clip (Ima
1259
1268
  Entities own fields; ordinary Relations express associations; variants directly hold baseEntityIds and assemble the referenced entities. These foundations are fixed: implementation must follow them, never redefine them. Any entity may compose multiple bases. Equal field names from multiple bases (even equal values) are errors, even when the variant declares that field itself. After validating all base fields are unambiguous, explicitly declared own fields may override base fields without mutating the bases. Base ordering never resolves conflicts. AudioScript owns segmented text. Caption and PhoneticScript persist baseEntityIds including their AudioScript, plus their own fields; no composition Relation exists. Create the real bases before reading or committing a variant. Inside the DSL sandbox, entities.get/list expose complete assembled fields. Consumers read fields without inspecting base IDs or merging bases. entities.update patches supplied fields and routes inherited fields to their declaring entity; omitted fields remain unchanged. entities.declareFields explicitly declares own overrides and is distinct from an ordinary field edit. Persistence keeps owned fields only. entities.readCaptionContent(id) and entities.readPhoneticScriptContent(id) return assembled text. Missing/cyclic bases and field conflicts fail before persistence.
1260
1269
  Use edit.insertCaptionClip with baseEntityIds and selections; each voiceover caption also supplies baseEntityIds. A selection names segmentId and may use a half-open Unicode code-point textRange to split a segment for the screen without rewriting AudioScript. Generate Voice from an existing PhoneticScript, then use phoneticScriptEntityId in the voiceover helper or relations.linkPhoneticScriptRender({output_entity_id,phonetic_script_entity_id}) for its render relation. Caption and Voice have their own Clips; display anchoring is explicit and independent of composition/alignment.
1261
1270
  Move or stretch only the Clip's display Marker; preserve Caption intrinsic Sequence, AudioScript text and its annotation Markers. AudioScript cannot enter a Clip and has no intrinsic time. audio-script-source links its ASR source Audio/Video/Voice; audio-script-marker attaches annotation Markers with directly assigned segmentRanges:{segmentId,startMs,endMs} in whole milliseconds. Annotation Markers have no Clip/AXVideo/content/Timeline relations and never refer to other Markers for time. BGM keeps factual source duration with durationPolicy:'timeline'. Never introduce a speech entity kind.
1262
- Create only the known entity kinds. The host initializes one Timeline and four fixed Tracks before editing; inspect and reuse their IDs from timeline.snapshot(), never create another Timeline or Track for each operation. If snapshot reports legacy migration is required, recall the listed asset facts and call migrate-legacy first. Missing facts, unsupported layouts, and version conflicts fail closed; never fall back to an old timeline method or raw update endpoint.
1271
+ Create only the known entity kinds. The host initializes one Timeline, four fixed Tracks, and the project's single AudioScript (initially segments:[]) before editing; inspect and reuse their IDs from timeline.snapshot(), never create another Timeline, Track, or AudioScript for each operation. The AudioScript identity is fixed for the project: edit its segments in place via entities.update, never delete or re-create it. If snapshot reports legacy migration is required, recall the listed asset facts and call migrate-legacy first. Missing facts, unsupported layouts, and version conflicts fail closed; never fall back to an old timeline method or raw update endpoint.
1263
1272
  Use only the globals and methods declared by the following TypeScript interface. Values not declared here are unavailable.
1264
1273
  `.trim();
1265
1274
  /** Render the complete MEngine-owned context injected before one model call. */
@@ -1614,7 +1623,7 @@ function renderEntitySnapshot(state) {
1614
1623
  const rows = [...state.entities.map((entity) => JSON.stringify(entity)), ...state.relations.map((relation) => JSON.stringify(relation))];
1615
1624
  const shown = rows.slice(0, 200);
1616
1625
  return [
1617
- `Entity revision=${state.revision} entities=${state.entities.length} relations=${state.relations.length}`,
1626
+ `Entity revision=${state.revision} audioScriptEntityId=${JSON.stringify(state.audioScriptEntityId)} entities=${state.entities.length} relations=${state.relations.length}`,
1618
1627
  ...shown,
1619
1628
  ...shown.length < rows.length ? ["[truncated; inspect entities/relations in the sandbox]"] : []
1620
1629
  ].join("\n");
@@ -1706,6 +1715,7 @@ function commitWarnings(result) {
1706
1715
  }
1707
1716
  function entityRowsEquivalent(left, right) {
1708
1717
  const normalize = (state) => ({
1718
+ audioScriptEntityId: state.audioScriptEntityId,
1709
1719
  entities: [...state.entities].sort((a, b) => a.entity_id.localeCompare(b.entity_id)).map((entity) => canonicalJson(entity)),
1710
1720
  relations: [...state.relations].sort((a, b) => a.relation_id.localeCompare(b.relation_id)).map((relation) => canonicalJson(relation))
1711
1721
  });
@@ -2055,23 +2065,26 @@ function createMedeoTool(options) {
2055
2065
  async function migrate(input) {
2056
2066
  return runExclusive(input.doc_id, async (doc) => {
2057
2067
  assertNoPendingPush(input.doc_id);
2058
- const client = getGraphClient(input.doc_id);
2059
- const base = await client.fetchState();
2060
- if (base.rows.entities.some((row) => row.entityKind === "timeline")) return {
2068
+ const snapshotState = await getEntityClient(input.doc_id).fetchState();
2069
+ if (snapshotState.entities.some((row) => row.entity_kind === "timeline")) return {
2061
2070
  ok: true,
2062
2071
  op: "migrate-legacy",
2063
2072
  doc_id: input.doc_id,
2064
2073
  migration_status: "already_entity",
2065
- entity_revision: base.revision,
2074
+ entity_revision: snapshotState.revision,
2066
2075
  next_action: "snapshot"
2067
2076
  };
2068
2077
  const pull = await doc.pull();
2069
2078
  if (!pull.ok) throw new Error(`Migration requires a fresh canonical snapshot: ${pull.error.message}`);
2070
2079
  const migrationBaseVv = encodeDocVersionMark(doc.versionMark());
2071
- const nextRows = migrateLegacyTimelineToEntities(doc.snapshot(), input.asset_facts, base.rows);
2080
+ const baseRows = toDslRows(snapshotState);
2081
+ const nextRows = migrateLegacyTimelineToEntities(doc.snapshot(), input.asset_facts, baseRows);
2072
2082
  let revision;
2073
2083
  try {
2074
- revision = (await client.commit(base, nextRows, { migrationBaseVv })).revision;
2084
+ revision = (await getGraphClient(input.doc_id).commit({
2085
+ revision: snapshotState.revision,
2086
+ rows: baseRows
2087
+ }, nextRows, { migrationBaseVv })).revision;
2075
2088
  } catch (error) {
2076
2089
  if (error instanceof MengineHttpRequestError) throw new Error(`Migration rejected (HTTP ${error.status}): ${entityHttpErrorMessage(error.payload)}; take a fresh snapshot before retrying`);
2077
2090
  throw new Error("Migration submission is unconfirmed; take a fresh snapshot and retry migrate-legacy to inspect whether the Entity timeline already exists");