@mengine/medeo-client 2.1.1-dsl.5 → 2.1.1-dsl.7

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.
@@ -327,6 +327,7 @@ function assertChangeAdmitted(change) {
327
327
  for (const field of referenceFields[table] ?? []) if (!old || fields.has(field)) assertReferenceAdmitted(after, table, id, field, row[field]);
328
328
  const marker = row.seqMarker;
329
329
  if (table === "clip-entities" && (!old || fields.has("seqMarker")) && marker?.outMs <= marker?.inMs) throw new Error("Clip window must be nonempty");
330
+ if (table === "clip-entities" && (!old || fields.has("seqMarker") || fields.has("source"))) assertFillsWithWholeSource(after, marker, row.source);
330
331
  }
331
332
  if (change.entities.has("timeline-entities") && Object.keys(after["timeline-entities"]).length > 1) throw new Error("Document already has a Timeline");
332
333
  for (const [table, ids] of change.relations) for (const id of ids) {
@@ -334,6 +335,16 @@ function assertChangeAdmitted(change) {
334
335
  if (value !== void 0) assertRelationAdmitted(after, table, id, value);
335
336
  }
336
337
  }
338
+ /**
339
+ * A Clip that fills the Timeline plays its whole source at 1×: the player loops a short source and
340
+ * cuts a long one at the Timeline's end (RFC 02 §3.3), so a window or speed of its own has no meaning.
341
+ */
342
+ function assertFillsWithWholeSource(rows, marker, source) {
343
+ if (marker?.fillTimeline !== true) return;
344
+ const media = typeof source === "string" ? rows["media-entities"][source] : void 0;
345
+ const durationMs = typeof media?.durationMs === "number" ? media.durationMs : void 0;
346
+ if (marker.inMs !== 0 || marker.rate !== void 0 && marker.rate !== 1 || durationMs !== void 0 && marker.outMs !== durationMs) throw new Error(`A Clip that fills the Timeline plays its whole source at 1×: inMs 0, outMs ${durationMs ?? "its length"}, no rate; the Timeline's end cuts it`);
347
+ }
337
348
  //#endregion
338
349
  //#region src/dsl/projection/types.ts
339
350
  /** Unsupported legacy representations fail explicitly; recoverable CRDT state is returned as diagnostics. */
@@ -5633,7 +5644,7 @@ function toVideoDraft(snapshot) {
5633
5644
  audio_storage_key: source.storageKey,
5634
5645
  origin_speech_id: source.key,
5635
5646
  volume: clip.volume,
5636
- audio_script: spokenText(snapshot, sourceId),
5647
+ audio_script: spokenText(snapshot, sourceId, captionIds),
5637
5648
  voice: voice ? {
5638
5649
  id: voice.key,
5639
5650
  name: voice.name
@@ -5718,11 +5729,30 @@ function toVideoDraft(snapshot) {
5718
5729
  function requireWholeAudio(media, clip, fail) {
5719
5730
  if (media.kind === "image" || clip.inMs !== 0 || clip.outMs !== media.durationMs || clip.rate !== 1) fail("VideoDraft audio has no trim or speed fields");
5720
5731
  }
5721
- function spokenText(snapshot, recordingId) {
5732
+ /**
5733
+ * The words a speech Clip says. A script voiced in several takes is said one part per take, and
5734
+ * the Captions following the Clip select that part: its words are the segments they select, in
5735
+ * script order. A Clip no Caption of its script follows says the whole script.
5736
+ */
5737
+ function spokenText(snapshot, recordingId, captionClipIds) {
5722
5738
  const scripts = new Set(spokenScripts(snapshot, recordingId).map((spoken) => spoken.audioScriptId));
5723
5739
  if (scripts.size > 1) projectionError("ambiguous-script", `media-entities/${recordingId}`, "Multiple scripts cannot be silently concatenated into audio_script");
5724
5740
  const id = [...scripts][0];
5725
- return id ? snapshot.richText[id]?.plainText ?? "" : "";
5741
+ if (!id) return "";
5742
+ const body = snapshot.richText[id]?.plainText ?? "";
5743
+ const segments = lines(body);
5744
+ const said = /* @__PURE__ */ new Set();
5745
+ for (const clipId of captionClipIds) {
5746
+ const captionId = snapshot["clip-entities"][clipId]?.source;
5747
+ const caption = captionId === void 0 ? void 0 : snapshot["caption-entities"][captionId];
5748
+ const shown = captionId === void 0 ? void 0 : snapshot.captionText[captionId];
5749
+ if (caption?.selection?.audioScriptId !== id || caption.text !== void 0 || !shown) continue;
5750
+ segments.forEach((line, index) => {
5751
+ if (shown.start < Math.max(line.end, line.start + 1) && shown.end > line.start) said.add(index);
5752
+ });
5753
+ }
5754
+ if (!said.size) return body;
5755
+ return [...said].sort((a, b) => a - b).map((index) => segments[index].text).join("\n");
5726
5756
  }
5727
5757
  //#endregion
5728
5758
  //#region src/dsl/projection/from-video-draft.ts
package/dist/dsl.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { a as documentFormat, c as isInvalidAtomic, ft as defaultIdFactory, ht as tupleHash, i as assertDslDocument, l as timeAnchorCodec, mt as resourceId, o as medeoDslLoroShape, pt as relationId, r as UnsupportedDocumentFormatError, s as captionContentCodec, t as DEFAULT_UNIT_TIME_MS } from "./video-draft-types-Ce8NDenQ.js";
2
- import { a as DslEditor, c as DslProjectionError, i as createInitialMedeoDsl, n as toVideoDraft, o as MedeoDsl, r as toAudioScriptViews, s as resolveDslLayout, t as fromVideoDraft } from "./dsl-DQ63zFgu.js";
2
+ import { a as DslEditor, c as DslProjectionError, i as createInitialMedeoDsl, n as toVideoDraft, o as MedeoDsl, r as toAudioScriptViews, s as resolveDslLayout, t as fromVideoDraft } from "./dsl-DbYqFFOb.js";
3
3
  export { DEFAULT_UNIT_TIME_MS, DslEditor, DslProjectionError, MedeoDsl, UnsupportedDocumentFormatError, assertDslDocument, captionContentCodec, createInitialMedeoDsl, defaultIdFactory, documentFormat, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, relationId, resolveDslLayout, resourceId, timeAnchorCodec, toAudioScriptViews, toVideoDraft, tupleHash };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { n as bytesToBase64, t as base64ToBytes } from "./base64-D-jd-dr5.js";
2
2
  import { a as covers, c as readMengineEventStream, d as MenginePushRejectedError, i as openManualDocument, l as MengineHttpClient, n as MedeoHttpDocStorage, o as decodeDocVersionMark, r as ManualSyncTransport, s as encodeDocVersionMark, t as MemoryDocStorage, u as MengineHttpRequestError } from "./storage-BW3tI_ER.js";
3
3
  import { a as documentFormat, c as isInvalidAtomic, ft as defaultIdFactory, ht as tupleHash, i as assertDslDocument, l as timeAnchorCodec, mt as resourceId, o as medeoDslLoroShape, pt as relationId, r as UnsupportedDocumentFormatError, s as captionContentCodec, t as DEFAULT_UNIT_TIME_MS } from "./video-draft-types-Ce8NDenQ.js";
4
- import { a as DslEditor, c as DslProjectionError, i as createInitialMedeoDsl, n as toVideoDraft, o as MedeoDsl, r as toAudioScriptViews, s as resolveDslLayout, t as fromVideoDraft } from "./dsl-DQ63zFgu.js";
4
+ import { a as DslEditor, c as DslProjectionError, i as createInitialMedeoDsl, n as toVideoDraft, o as MedeoDsl, r as toAudioScriptViews, s as resolveDslLayout, t as fromVideoDraft } from "./dsl-DbYqFFOb.js";
5
5
  import { UndoManager, VersionVector, decodeImportBlobMeta } from "loro-crdt";
6
6
  import { ClientServerSynchronizer, DocManager } from "@mengine/sync";
7
7
  import { DisposableSet, EventBus } from "@mengine/utils";
package/dist/testing.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as bytesToBase64, t as base64ToBytes } from "./base64-D-jd-dr5.js";
2
2
  import { a as documentFormat, i as assertDslDocument } from "./video-draft-types-Ce8NDenQ.js";
3
- import { a as DslEditor, i as createInitialMedeoDsl, n as toVideoDraft, o as MedeoDsl } from "./dsl-DQ63zFgu.js";
3
+ import { a as DslEditor, i as createInitialMedeoDsl, n as toVideoDraft, o as MedeoDsl } from "./dsl-DbYqFFOb.js";
4
4
  import { t as classifyUpdate } from "./loro-relay-doc-Bi6JKqtQ.js";
5
5
  import { LoroDoc, VersionVector, encodeFrontiers } from "loro-crdt";
6
6
  //#region src/testing/in-memory-mengine-server.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mengine/medeo-client",
3
- "version": "2.1.1-dsl.5",
3
+ "version": "2.1.1-dsl.7",
4
4
  "license": "UNLICENSED",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,9 +29,9 @@
29
29
  "@noble/hashes": "^2.4.0",
30
30
  "immer": "^10.2.0",
31
31
  "zod": "^4.4.3",
32
- "@mengine/storage": "2.1.1-dsl.5",
33
- "@mengine/utils": "2.1.1-dsl.5",
34
- "@mengine/sync": "2.1.1-dsl.5"
32
+ "@mengine/storage": "2.1.1-dsl.7",
33
+ "@mengine/sync": "2.1.1-dsl.7",
34
+ "@mengine/utils": "2.1.1-dsl.7"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/node": "^25.9.1",