@mengine/medeo-client 2.1.1-dsl.4 → 2.1.1-dsl.6

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.
@@ -1,4 +1,4 @@
1
- import { $ as assertId, A as hardenCidDescriptors, B as safeStringify, C as applySchemaToInferOptions, D as deepEqual, E as decodeNestedJsonValues, F as isObject, G as valuesEqual, H as stripUndefined, I as isObjectLike, J as getChildSchema, K as CID_KEY, L as isStateAndSchemaOfType, M as inferContainerTypeFromValue, N as insertChildToMap, O as defineCidProperty, P as isArrayLike, Q as assertEntityPatch, R as isTreeID, S as applyEncode, T as containerIdToContainerType, U as tryInferContainerType, V as schemaToContainerType, W as tryUpdateToContainer, X as assertCaptionContent, Y as getMapFieldSchema, Z as assertEntity, _ as isLoroTreeSchema, at as isRecord, b as validateSchema, c as isInvalidAtomic, ct as relationTables, d as getDefaultValue, dt as assertResourceIdentity, et as assertPhoneme, f as isContainerSchema, ft as defaultIdFactory, g as isLoroMovableListSchema, h as isLoroMapSchema, it as entityTables, j as hasTransform, k as getRootContainerByType, lt as validLanguage, m as isLoroListSchema, mt as resourceId, n as textStyles, nt as assertTimeAnchor, o as medeoDslLoroShape, ot as mergeFields, p as isListLikeSchema, pt as relationId, q as getChildContainerSchema, rt as atomicFields, s as captionContentCodec, st as patchRow, t as DEFAULT_UNIT_TIME_MS, tt as assertRelation, u as schema, ut as assertRelationIdentity, v as isRootSchemaType, w as cidsEqual, x as applyDecode, y as schemaContainsIgnoreField, z as isValueOfContainerType } from "./video-draft-types-DvPeam87.js";
1
+ import { $ as assertId, A as hardenCidDescriptors, B as safeStringify, C as applySchemaToInferOptions, D as deepEqual, E as decodeNestedJsonValues, F as isObject, G as valuesEqual, H as stripUndefined, I as isObjectLike, J as getChildSchema, K as CID_KEY, L as isStateAndSchemaOfType, M as inferContainerTypeFromValue, N as insertChildToMap, O as defineCidProperty, P as isArrayLike, Q as assertEntityPatch, R as isTreeID, S as applyEncode, T as containerIdToContainerType, U as tryInferContainerType, V as schemaToContainerType, W as tryUpdateToContainer, X as assertCaptionContent, Y as getMapFieldSchema, Z as assertEntity, _ as isLoroTreeSchema, at as isRecord, b as validateSchema, c as isInvalidAtomic, ct as relationTables, d as getDefaultValue, dt as assertResourceIdentity, et as assertPhoneme, f as isContainerSchema, ft as defaultIdFactory, g as isLoroMovableListSchema, h as isLoroMapSchema, it as entityTables, j as hasTransform, k as getRootContainerByType, lt as validLanguage, m as isLoroListSchema, mt as resourceId, n as textStyles, nt as assertTimeAnchor, o as medeoDslLoroShape, ot as mergeFields, p as isListLikeSchema, pt as relationId, q as getChildContainerSchema, rt as atomicFields, s as captionContentCodec, st as patchRow, t as DEFAULT_UNIT_TIME_MS, tt as assertRelation, u as schema, ut as assertRelationIdentity, v as isRootSchemaType, w as cidsEqual, x as applyDecode, y as schemaContainsIgnoreField, z as isValueOfContainerType } from "./video-draft-types-Ce8NDenQ.js";
2
2
  import { Cursor, LoroDoc, LoroList, LoroMap, LoroMovableList, LoroText, LoroTree, isContainer, isContainerId } from "loro-crdt";
3
3
  import { Immer, setAutoFreeze } from "immer";
4
4
  //#region ../medeo-dsl/src/text.ts
@@ -107,6 +107,42 @@ function prepareTextEdits(text, edits) {
107
107
  body: text
108
108
  };
109
109
  }
110
+ /** An empty body has no segments; otherwise each line, including a trailing empty one, is a segment. */
111
+ function lines(body) {
112
+ if (body === "") return [];
113
+ const result = [];
114
+ let start = 0;
115
+ for (const text of body.split("\n")) {
116
+ result.push({
117
+ text,
118
+ start,
119
+ end: start + text.length
120
+ });
121
+ start += text.length + 1;
122
+ }
123
+ return result;
124
+ }
125
+ /** The language a whole line carries: one shared mark on every unit, else none. */
126
+ function lineLanguage(text, line) {
127
+ if (line.start === line.end) return void 0;
128
+ const first = text.langs[line.start];
129
+ for (let i = line.start + 1; i < line.end; i++) if (text.langs[i] !== first) return void 0;
130
+ return first;
131
+ }
132
+ /** Read language marks off a rich-text delta. */
133
+ function langsFromDelta(delta) {
134
+ let body = "";
135
+ const langs = [];
136
+ for (const run of delta) {
137
+ body += run.insert;
138
+ const language = typeof run.attributes?.language === "string" ? run.attributes.language : void 0;
139
+ for (let i = 0; i < run.insert.length; i++) langs.push(language);
140
+ }
141
+ return {
142
+ body,
143
+ langs
144
+ };
145
+ }
110
146
  //#endregion
111
147
  //#region ../medeo-dsl/src/relations.ts
112
148
  /** The row an endpoint names; refused when it is missing. */
@@ -291,6 +327,7 @@ function assertChangeAdmitted(change) {
291
327
  for (const field of referenceFields[table] ?? []) if (!old || fields.has(field)) assertReferenceAdmitted(after, table, id, field, row[field]);
292
328
  const marker = row.seqMarker;
293
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);
294
331
  }
295
332
  if (change.entities.has("timeline-entities") && Object.keys(after["timeline-entities"]).length > 1) throw new Error("Document already has a Timeline");
296
333
  for (const [table, ids] of change.relations) for (const id of ids) {
@@ -298,6 +335,16 @@ function assertChangeAdmitted(change) {
298
335
  if (value !== void 0) assertRelationAdmitted(after, table, id, value);
299
336
  }
300
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
+ }
301
348
  //#endregion
302
349
  //#region src/dsl/projection/types.ts
303
350
  /** Unsupported legacy representations fail explicitly; recoverable CRDT state is returned as diagnostics. */
@@ -4261,7 +4308,7 @@ function applyMutations(tx, mutations) {
4261
4308
  assertRelation(m.table, m.value);
4262
4309
  const id = relationId(m.table, m.value);
4263
4310
  rows[m.table][id] ??= {};
4264
- applyPatch(rows[m.table][id], m.value);
4311
+ applyPatch(rows[m.table][id], withSourceDigest(rows, m.table, m.value));
4265
4312
  break;
4266
4313
  }
4267
4314
  case "delete-relation":
@@ -4280,6 +4327,25 @@ function applyMutations(tx, mutations) {
4280
4327
  }
4281
4328
  }
4282
4329
  }
4330
+ /**
4331
+ * A derived-from records its source's digest (D177): the one the writer names, otherwise the
4332
+ * source's digest as this transaction leaves it. A source with no digest records none.
4333
+ */
4334
+ function withSourceDigest(rows, table, value) {
4335
+ if (table !== "derived-from-relations") return value;
4336
+ const relation = value;
4337
+ if (relation.sourceDigest !== void 0) return value;
4338
+ const sourceDigest = digestOf(rows, relation.sourceId);
4339
+ return sourceDigest === void 0 ? value : {
4340
+ ...relation,
4341
+ sourceDigest
4342
+ };
4343
+ }
4344
+ /** A source's digest is its file's: a PhoneticScript's or a medium's Media File `digest`. */
4345
+ function digestOf(rows, entityId) {
4346
+ const digest = (rows["phonetic-script-entities"][entityId] ?? rows["media-entities"][entityId])?.digest;
4347
+ return typeof digest === "string" ? digest : void 0;
4348
+ }
4283
4349
  //#endregion
4284
4350
  //#region src/dsl/document/native-text.ts
4285
4351
  function applyTextEdits(text, edits) {
@@ -4764,6 +4830,8 @@ function voiceoverPlan(s, input, result) {
4764
4830
  }
4765
4831
  });
4766
4832
  else if (!s["audio-script-entities"][result.audioScriptId]) throw new Error("Missing AudioScript");
4833
+ const phoneticScriptId = input.script.phoneticScriptId;
4834
+ if (phoneticScriptId !== void 0 && s["phonetic-script-entities"][phoneticScriptId]?.phoneme.audioScriptId !== result.audioScriptId) throw new Error("The PhoneticScript must name this AudioScript as its base");
4767
4835
  validateWindow({
4768
4836
  inMs: 0,
4769
4837
  outMs: input.media.durationMs
@@ -4773,7 +4841,8 @@ function voiceoverPlan(s, input, result) {
4773
4841
  table: "derived-from-relations",
4774
4842
  value: {
4775
4843
  entityId: result.mediaId,
4776
- sourceId: result.audioScriptId
4844
+ sourceId: phoneticScriptId ?? result.audioScriptId,
4845
+ ...input.sourceDigest === void 0 ? {} : { sourceDigest: input.sourceDigest }
4777
4846
  }
4778
4847
  });
4779
4848
  if (input.voice) {
@@ -4899,9 +4968,11 @@ function voiceoverPlan(s, input, result) {
4899
4968
  var DslEditor = class {
4900
4969
  dsl;
4901
4970
  idFactory;
4902
- constructor(dsl, idFactory = defaultIdFactory) {
4971
+ uploadText;
4972
+ constructor(dsl, idFactory = defaultIdFactory, uploadText) {
4903
4973
  this.dsl = dsl;
4904
4974
  this.idFactory = idFactory;
4975
+ this.uploadText = uploadText;
4905
4976
  }
4906
4977
  createTrack(role, options) {
4907
4978
  const id = this.idFactory("track");
@@ -5191,7 +5262,7 @@ var DslEditor = class {
5191
5262
  const result = {
5192
5263
  clipId: input.clipId ?? this.idFactory("clip"),
5193
5264
  mediaId: resourceId("media", input.media.system, input.media.key),
5194
- audioScriptId: input.script.audioScriptId ?? this.idFactory("audio-script"),
5265
+ audioScriptId: this.voiceoverScriptId(input.script),
5195
5266
  captionClipIds: input.captions.map((c) => c.clipId ?? this.idFactory("clip")),
5196
5267
  captionIds: input.captions.map(() => this.idFactory("caption"))
5197
5268
  };
@@ -5201,6 +5272,71 @@ var DslEditor = class {
5201
5272
  }, voiceoverPlan(this.dsl.getSnapshot(), input, result), options);
5202
5273
  return result;
5203
5274
  }
5275
+ voiceoverScriptId(script) {
5276
+ if (script.audioScriptId !== void 0) return script.audioScriptId;
5277
+ if (script.phoneticScriptId === void 0) return this.idFactory("audio-script");
5278
+ const phonetic = this.dsl.getSnapshot()["phonetic-script-entities"][script.phoneticScriptId];
5279
+ if (!phonetic) throw new Error("Missing PhoneticScript");
5280
+ return phonetic.phoneme.audioScriptId;
5281
+ }
5282
+ /**
5283
+ * Write a PhoneticScript: create one for `audioScriptId`, or, given `phoneticScriptId`, replace its
5284
+ * base and pronunciation together. A `phonemeScript` is stored as a Memota text file first, and
5285
+ * the file's facts are written with it; an unchanged one keeps its file. Recordings already spoken
5286
+ * from it keep their derived-from.
5287
+ */
5288
+ async setPhoneticScript(input, options) {
5289
+ const id = input.phoneticScriptId ?? this.idFactory("phonetic-script");
5290
+ const phoneme = {
5291
+ audioScriptId: input.audioScriptId,
5292
+ ...input.phonemeScript === void 0 ? {} : { phonemeScript: input.phonemeScript }
5293
+ };
5294
+ const file = input.phonemeScript === void 0 ? {} : await this.fileFor(id, input.phonemeScript);
5295
+ const exists = Object.hasOwn(this.dsl.getSnapshot()["phonetic-script-entities"], id);
5296
+ const cleared = {
5297
+ system: void 0,
5298
+ key: void 0,
5299
+ storageKey: void 0,
5300
+ digest: void 0
5301
+ };
5302
+ this.write("setPhoneticScript", {
5303
+ id,
5304
+ phoneme,
5305
+ ...cleared,
5306
+ ...file
5307
+ }, [exists ? {
5308
+ type: "patch-entity",
5309
+ table: "phonetic-script-entities",
5310
+ id,
5311
+ patch: {
5312
+ phoneme: {
5313
+ ...phoneme,
5314
+ phonemeScript: input.phonemeScript
5315
+ },
5316
+ ...cleared,
5317
+ ...file
5318
+ }
5319
+ } : {
5320
+ type: "create-entity",
5321
+ table: "phonetic-script-entities",
5322
+ id,
5323
+ value: {
5324
+ phoneme,
5325
+ ...file
5326
+ }
5327
+ }], options);
5328
+ return id;
5329
+ }
5330
+ /** The file holding `text`: the one the PhoneticScript keeps while its text is unchanged, else a new upload. */
5331
+ async fileFor(id, text) {
5332
+ const current = this.dsl.getSnapshot()["phonetic-script-entities"][id];
5333
+ if (current?.phoneme.phonemeScript === text) {
5334
+ const { phoneme: _, ...file } = current;
5335
+ return file;
5336
+ }
5337
+ if (!this.uploadText) throw new Error("This editor stores no files");
5338
+ return this.uploadText(text);
5339
+ }
5204
5340
  setBgm(input, options) {
5205
5341
  const s = this.dsl.getSnapshot();
5206
5342
  if (requireTrack(s, input.trackId).role !== "bgm") throw new Error("Expected a BGM Track");
@@ -5295,6 +5431,131 @@ function createInitialMedeoDsl(options = {}) {
5295
5431
  }
5296
5432
  }
5297
5433
  //#endregion
5434
+ //#region src/dsl/projection/audio-scripts.ts
5435
+ /**
5436
+ * The scripts a recording says. It follows derived-from from the recording; a PhoneticScript is a
5437
+ * variant, so its words are the base its phoneme names, and derived-from is not followed past it.
5438
+ * When nothing is found that way, a script read off the recording itself is what it says.
5439
+ */
5440
+ function spokenScripts(snapshot, recordingId) {
5441
+ const relations = Object.values(snapshot["derived-from-relations"]);
5442
+ const found = /* @__PURE__ */ new Map();
5443
+ const seen = /* @__PURE__ */ new Set();
5444
+ const visit = (id, phoneticScriptId) => {
5445
+ if (seen.has(id)) return;
5446
+ seen.add(id);
5447
+ if (snapshot["audio-script-entities"][id]) {
5448
+ if (!found.has(id)) found.set(id, phoneticScriptId);
5449
+ return;
5450
+ }
5451
+ const phonetic = snapshot["phonetic-script-entities"][id];
5452
+ if (phonetic) {
5453
+ visit(phonetic.phoneme.audioScriptId, id);
5454
+ return;
5455
+ }
5456
+ for (const r of relations) if (r.entityId === id) visit(r.sourceId, phoneticScriptId);
5457
+ };
5458
+ visit(recordingId);
5459
+ if (!found.size) {
5460
+ for (const r of relations) if (r.sourceId === recordingId && snapshot["audio-script-entities"][r.entityId]) found.set(r.entityId, void 0);
5461
+ }
5462
+ return [...found].map(([audioScriptId, phoneticScriptId]) => phoneticScriptId === void 0 ? { audioScriptId } : {
5463
+ audioScriptId,
5464
+ phoneticScriptId
5465
+ });
5466
+ }
5467
+ /** Every AudioScript in the document with its PhoneticScripts, the Speech Clips saying it and the Caption Clips showing it. */
5468
+ function toAudioScriptViews(snapshot) {
5469
+ const views = /* @__PURE__ */ new Map();
5470
+ const bodies = /* @__PURE__ */ new Map();
5471
+ for (const [id, script] of Object.entries(snapshot["audio-script-entities"])) {
5472
+ const rich = snapshot.richText[id];
5473
+ const text = rich ? langsFromDelta(rich.delta) : {
5474
+ body: script.body,
5475
+ langs: []
5476
+ };
5477
+ bodies.set(id, text.body);
5478
+ views.set(id, {
5479
+ id,
5480
+ segments: lines(text.body).map((line) => {
5481
+ const language = lineLanguage(text, line);
5482
+ return language === void 0 ? { text: line.text } : {
5483
+ text: line.text,
5484
+ language
5485
+ };
5486
+ }),
5487
+ sourceMediaIds: [],
5488
+ phoneticScripts: [],
5489
+ speeches: [],
5490
+ captions: []
5491
+ });
5492
+ }
5493
+ for (const r of Object.values(snapshot["derived-from-relations"])) if (snapshot["media-entities"][r.sourceId]) views.get(r.entityId)?.sourceMediaIds.push(r.sourceId);
5494
+ for (const [id, phonetic] of Object.entries(snapshot["phonetic-script-entities"])) {
5495
+ const { phonemeScript } = phonetic.phoneme;
5496
+ const { digest } = phonetic;
5497
+ views.get(phonetic.phoneme.audioScriptId)?.phoneticScripts.push({
5498
+ id,
5499
+ ...phonemeScript === void 0 ? {} : { phonemeScript },
5500
+ ...digest === void 0 ? {} : { digest }
5501
+ });
5502
+ }
5503
+ const timbres = Object.values(snapshot["voice-timbre-relations"]);
5504
+ for (const track of resolveDslLayout(snapshot).tracks) for (const { clipId } of track.clips) {
5505
+ const source = snapshot["clip-entities"][clipId]?.source;
5506
+ if (!source) continue;
5507
+ if (snapshot["media-entities"][source]?.kind === "voiceover-recording") {
5508
+ const voices = timbres.filter((r) => r.recordingId === source).flatMap((r) => {
5509
+ const voice = snapshot["voice-entities"][r.voiceId];
5510
+ if (!voice) return [];
5511
+ return [voice.name === void 0 ? {
5512
+ voiceId: r.voiceId,
5513
+ key: voice.key
5514
+ } : {
5515
+ voiceId: r.voiceId,
5516
+ key: voice.key,
5517
+ name: voice.name
5518
+ }];
5519
+ });
5520
+ for (const spoken of spokenScripts(snapshot, source)) {
5521
+ const applied = appliedSpeech(snapshot, source, spoken);
5522
+ views.get(spoken.audioScriptId)?.speeches.push({
5523
+ clipId,
5524
+ recordingId: source,
5525
+ ...spoken.phoneticScriptId === void 0 ? {} : { phoneticScriptId: spoken.phoneticScriptId },
5526
+ voices,
5527
+ ...applied === void 0 ? {} : { applied }
5528
+ });
5529
+ }
5530
+ continue;
5531
+ }
5532
+ const caption = snapshot["caption-entities"][source];
5533
+ const shown = snapshot.captionText[source];
5534
+ if (!caption?.selection || caption.text !== void 0 || !shown) continue;
5535
+ const scriptId = caption.selection.audioScriptId;
5536
+ const body = bodies.get(scriptId);
5537
+ if (body === void 0) continue;
5538
+ const segment = lines(body).findIndex((line) => shown.start >= line.start && shown.end <= line.end);
5539
+ if (segment >= 0) views.get(scriptId)?.captions.push({
5540
+ clipId,
5541
+ captionId: source,
5542
+ segment
5543
+ });
5544
+ }
5545
+ return [...views.values()];
5546
+ }
5547
+ /**
5548
+ * Whether a recording still matches what it was synthesized from: the digest its derived-from
5549
+ * records against the source's file digest now. An AudioScript has no file, so a recording
5550
+ * derived from a script directly is not judged.
5551
+ */
5552
+ function appliedSpeech(snapshot, recordingId, spoken) {
5553
+ const sourceId = spoken.phoneticScriptId ?? spoken.audioScriptId;
5554
+ const recorded = Object.values(snapshot["derived-from-relations"]).find((r) => r.entityId === recordingId && r.sourceId === sourceId)?.sourceDigest;
5555
+ const current = spoken.phoneticScriptId === void 0 ? void 0 : snapshot["phonetic-script-entities"][sourceId]?.digest;
5556
+ return recorded === void 0 || current === void 0 ? void 0 : recorded === current;
5557
+ }
5558
+ //#endregion
5298
5559
  //#region src/dsl/projection/caption-style.ts
5299
5560
  const fields = {
5300
5561
  fontSize: "font_size",
@@ -5383,7 +5644,7 @@ function toVideoDraft(snapshot) {
5383
5644
  audio_storage_key: source.storageKey,
5384
5645
  origin_speech_id: source.key,
5385
5646
  volume: clip.volume,
5386
- audio_script: spokenText(snapshot, sourceId),
5647
+ audio_script: spokenText(snapshot, sourceId, captionIds),
5387
5648
  voice: voice ? {
5388
5649
  id: voice.key,
5389
5650
  name: voice.name
@@ -5468,30 +5729,30 @@ function toVideoDraft(snapshot) {
5468
5729
  function requireWholeAudio(media, clip, fail) {
5469
5730
  if (media.kind === "image" || clip.inMs !== 0 || clip.outMs !== media.durationMs || clip.rate !== 1) fail("VideoDraft audio has no trim or speed fields");
5470
5731
  }
5471
- function spokenText(snapshot, recordingId) {
5472
- const relations = Object.values(snapshot["derived-from-relations"]);
5473
- const scripts = /* @__PURE__ */ new Set(), seen = /* @__PURE__ */ new Set();
5474
- const visit = (id) => {
5475
- if (seen.has(id)) return;
5476
- seen.add(id);
5477
- if (snapshot["audio-script-entities"][id]) {
5478
- scripts.add(id);
5479
- return;
5480
- }
5481
- const phonetic = snapshot["phonetic-script-entities"][id];
5482
- if (phonetic) {
5483
- visit(phonetic.phoneme.audioScriptId);
5484
- return;
5485
- }
5486
- for (const r of relations) if (r.entityId === id) visit(r.sourceId);
5487
- };
5488
- visit(recordingId);
5489
- if (!scripts.size) {
5490
- for (const r of relations) if (r.sourceId === recordingId && snapshot["audio-script-entities"][r.entityId]) scripts.add(r.entityId);
5491
- }
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) {
5738
+ const scripts = new Set(spokenScripts(snapshot, recordingId).map((spoken) => spoken.audioScriptId));
5492
5739
  if (scripts.size > 1) projectionError("ambiguous-script", `media-entities/${recordingId}`, "Multiple scripts cannot be silently concatenated into audio_script");
5493
5740
  const id = [...scripts][0];
5494
- 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");
5495
5756
  }
5496
5757
  //#endregion
5497
5758
  //#region src/dsl/projection/from-video-draft.ts
@@ -5807,4 +6068,4 @@ function milliseconds(value, path, positive = false, signed = false) {
5807
6068
  return value;
5808
6069
  }
5809
6070
  //#endregion
5810
- export { MedeoDsl as a, DslEditor as i, toVideoDraft as n, resolveDslLayout as o, createInitialMedeoDsl as r, DslProjectionError as s, fromVideoDraft as t };
6071
+ export { DslEditor as a, DslProjectionError as c, createInitialMedeoDsl as i, toVideoDraft as n, MedeoDsl as o, toAudioScriptViews as r, resolveDslLayout as s, fromVideoDraft as t };
package/dist/dsl.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { $ as TrackRole, A as DeepReadonly, B as RelationMutation, C as CaptionContent, D as Clip, E as CaptionText, F as EntityTables, G as RichTextSnapshot, H as RelationTables, I as EntityValues, J as TextMark, K as TextDelta, L as FieldPatch, M as DslMutation, N as EntityMutation, O as ContainMutation, P as EntityTable, Q as Track, R as MedeoDslSnapshot, S as Caption, T as CaptionStyle, U as RelationValues, V as RelationTable, W as ResourceSystem, X as TextRun, Y as TextMutation, Z as TimeAnchor, _ as defaultIdFactory, a as VideoDraftCaptionStyle, b as tupleHash, c as VideoDraftInput, d as VideoDraftTrack, et as Voice, f as VideoDraftTrackItem, g as EntityIdKind, h as DslIdFactory, i as VideoDraft, j as DslDiagnostic, k as ContainNode, l as VideoDraftPartUnion, m as OpActor, n as DEFAULT_UNIT_TIME_MS, o as VideoDraftContent, p as CommitOptions, q as TextEdit, r as VideoCreationSettings, s as VideoDraftContentPartUnion, t as CaptionDisplayCue, u as VideoDraftTimeline, v as relationId, w as CaptionSelection, x as AudioScript, y as resourceId, z as Media } from "./video-draft-types-BfkIuW5f.js";
2
- import { A as AddDslClip, C as InvalidAtomic, D as MedeoDslDraft, E as timeAnchorCodec, F as ReplaceDslClipsInput, I as ClipPlacement, M as ClipSource, N as DslClipUpdate, O as MedeoDslLoroState, P as MoveDslClipsInput, S as documentFormat, T as isInvalidAtomic, _ as MedeoDsl, a as toVideoDraft, b as UnsupportedDocumentFormatError, c as DslLayout, d as createInitialMedeoDsl, f as DslEditor, g as CreateMedeoDslOptions, h as VoiceoverResult, i as VideoDraftProjection, j as AddDslClipsInput, k as medeoDslLoroShape, l as DslProjectionError, m as VoiceoverCaptionInput, n as ImportedVideoDraft, o as resolveDslLayout, p as ApplyVoiceoverInput, r as fromVideoDraft, s as DslClipLayout, t as FromVideoDraftOptions, u as DslTrackLayout, v as DslAudit, w as captionContentCodec, x as assertDslDocument, y as DslTransaction } from "./index-DP9FG0z_.js";
3
- export { type AddDslClip, type AddDslClipsInput, type ApplyVoiceoverInput, type AudioScript, type Caption, type CaptionContent, type CaptionDisplayCue, type CaptionSelection, type CaptionStyle, type CaptionText, type Clip, type ClipPlacement, type ClipSource, type CommitOptions, type ContainMutation, type ContainNode, type CreateMedeoDslOptions, DEFAULT_UNIT_TIME_MS, type DeepReadonly, type DslAudit, type DslClipLayout, type DslClipUpdate, type DslDiagnostic, DslEditor, type DslIdFactory, type DslLayout, type DslMutation, DslProjectionError, type DslTrackLayout, type DslTransaction, type EntityIdKind, type EntityMutation, type EntityTable, type EntityTables, type EntityValues, type FieldPatch, type FromVideoDraftOptions, type ImportedVideoDraft, type InvalidAtomic, MedeoDsl, type MedeoDslDraft, type MedeoDslLoroState, type MedeoDslSnapshot, type Media, type MoveDslClipsInput, type OpActor, type RelationMutation, type RelationTable, type RelationTables, type RelationValues, type ReplaceDslClipsInput, type ResourceSystem, type RichTextSnapshot, type TextDelta, type TextEdit, type TextMark, type TextMutation, type TextRun, type TimeAnchor, type Track, type TrackRole, UnsupportedDocumentFormatError, type VideoCreationSettings, type VideoDraft, type VideoDraftCaptionStyle, type VideoDraftContent, type VideoDraftContentPartUnion, type VideoDraftInput, type VideoDraftPartUnion, type VideoDraftProjection, type VideoDraftTimeline, type VideoDraftTrack, type VideoDraftTrackItem, type Voice, type VoiceoverCaptionInput, type VoiceoverResult, assertDslDocument, captionContentCodec, createInitialMedeoDsl, defaultIdFactory, documentFormat, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, relationId, resolveDslLayout, resourceId, timeAnchorCodec, toVideoDraft, tupleHash };
1
+ import { $ as Track, A as DeepReadonly, B as RelationMutation, C as CaptionContent, D as Clip, E as CaptionText, F as EntityTables, G as RichTextSnapshot, H as RelationTables, I as EntityValues, J as TextEdit, K as StoredFile, L as FieldPatch, M as DslMutation, N as EntityMutation, O as ContainMutation, P as EntityTable, Q as TimeAnchor, R as MedeoDslSnapshot, S as Caption, T as CaptionStyle, U as RelationValues, V as RelationTable, W as ResourceSystem, X as TextMutation, Y as TextMark, Z as TextRun, _ as defaultIdFactory, a as VideoDraftCaptionStyle, b as tupleHash, c as VideoDraftInput, d as VideoDraftTrack, et as TrackRole, f as VideoDraftTrackItem, g as EntityIdKind, h as DslIdFactory, i as VideoDraft, j as DslDiagnostic, k as ContainNode, l as VideoDraftPartUnion, m as OpActor, n as DEFAULT_UNIT_TIME_MS, o as VideoDraftContent, p as CommitOptions, q as TextDelta, r as VideoCreationSettings, s as VideoDraftContentPartUnion, t as CaptionDisplayCue, tt as Voice, u as VideoDraftTimeline, v as relationId, w as CaptionSelection, x as AudioScript, y as resourceId, z as Media } from "./video-draft-types-Bq15tPBP.js";
2
+ import { A as MedeoDslDraft, C as UnsupportedDocumentFormatError, D as captionContentCodec, E as InvalidAtomic, F as ClipSource, I as DslClipUpdate, L as MoveDslClipsInput, M as medeoDslLoroShape, N as AddDslClip, O as isInvalidAtomic, P as AddDslClipsInput, R as ReplaceDslClipsInput, S as DslTransaction, T as documentFormat, _ as VoiceoverCaptionInput, a as toAudioScriptViews, b as MedeoDsl, c as resolveDslLayout, d as DslProjectionError, f as DslTrackLayout, g as ApplyVoiceoverInput, h as UploadText, i as AudioScriptView, j as MedeoDslLoroState, k as timeAnchorCodec, l as DslClipLayout, m as DslEditor, n as ImportedVideoDraft, o as VideoDraftProjection, p as createInitialMedeoDsl, r as fromVideoDraft, s as toVideoDraft, t as FromVideoDraftOptions, u as DslLayout, v as VoiceoverResult, w as assertDslDocument, x as DslAudit, y as CreateMedeoDslOptions, z as ClipPlacement } from "./index-DHcMMn2M.js";
3
+ export { type AddDslClip, type AddDslClipsInput, type ApplyVoiceoverInput, type AudioScript, type AudioScriptView, type Caption, type CaptionContent, type CaptionDisplayCue, type CaptionSelection, type CaptionStyle, type CaptionText, type Clip, type ClipPlacement, type ClipSource, type CommitOptions, type ContainMutation, type ContainNode, type CreateMedeoDslOptions, DEFAULT_UNIT_TIME_MS, type DeepReadonly, type DslAudit, type DslClipLayout, type DslClipUpdate, type DslDiagnostic, DslEditor, type DslIdFactory, type DslLayout, type DslMutation, DslProjectionError, type DslTrackLayout, type DslTransaction, type EntityIdKind, type EntityMutation, type EntityTable, type EntityTables, type EntityValues, type FieldPatch, type FromVideoDraftOptions, type ImportedVideoDraft, type InvalidAtomic, MedeoDsl, type MedeoDslDraft, type MedeoDslLoroState, type MedeoDslSnapshot, type Media, type MoveDslClipsInput, type OpActor, type RelationMutation, type RelationTable, type RelationTables, type RelationValues, type ReplaceDslClipsInput, type ResourceSystem, type RichTextSnapshot, type StoredFile, type TextDelta, type TextEdit, type TextMark, type TextMutation, type TextRun, type TimeAnchor, type Track, type TrackRole, UnsupportedDocumentFormatError, type UploadText, type VideoCreationSettings, type VideoDraft, type VideoDraftCaptionStyle, type VideoDraftContent, type VideoDraftContentPartUnion, type VideoDraftInput, type VideoDraftPartUnion, type VideoDraftProjection, type VideoDraftTimeline, type VideoDraftTrack, type VideoDraftTrackItem, type Voice, type VoiceoverCaptionInput, type VoiceoverResult, assertDslDocument, captionContentCodec, createInitialMedeoDsl, defaultIdFactory, documentFormat, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, relationId, resolveDslLayout, resourceId, timeAnchorCodec, toAudioScriptViews, toVideoDraft, tupleHash };
package/dist/dsl.js CHANGED
@@ -1,3 +1,3 @@
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-DvPeam87.js";
2
- import { a as MedeoDsl, i as DslEditor, n as toVideoDraft, o as resolveDslLayout, r as createInitialMedeoDsl, s as DslProjectionError, t as fromVideoDraft } from "./dsl-BCcld0Ca.js";
3
- export { DEFAULT_UNIT_TIME_MS, DslEditor, DslProjectionError, MedeoDsl, UnsupportedDocumentFormatError, assertDslDocument, captionContentCodec, createInitialMedeoDsl, defaultIdFactory, documentFormat, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, relationId, resolveDslLayout, resourceId, timeAnchorCodec, toVideoDraft, tupleHash };
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-DbYqFFOb.js";
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 };
@@ -1,6 +1,6 @@
1
- import { $ as TrackRole, R as MedeoDslSnapshot, W as ResourceSystem } from "./video-draft-types-BfkIuW5f.js";
2
- import { _ as MedeoDsl, f as DslEditor, i as VideoDraftProjection } from "./index-DP9FG0z_.js";
3
- import { _ as ManualSyncTransport, a as MengineDocSessionOptions, g as ManualSyncDocOptions, n as DocumentSession, r as DocumentSessionUpdateEvent } from "./index-CwG4lYKp.js";
1
+ import { R as MedeoDslSnapshot, W as ResourceSystem, et as TrackRole } from "./video-draft-types-Bq15tPBP.js";
2
+ import { b as MedeoDsl, h as UploadText, i as AudioScriptView, m as DslEditor, o as VideoDraftProjection } from "./index-DHcMMn2M.js";
3
+ import { _ as ManualSyncTransport, a as MengineDocSessionOptions, g as ManualSyncDocOptions, n as DocumentSession, r as DocumentSessionUpdateEvent } from "./index-Dpl4bT94.js";
4
4
 
5
5
  //#region src/manual-sync/manual-sync-doc.d.ts
6
6
  /** Explicit synchronization over the same DSL/editor used by the live Session. */
@@ -8,7 +8,10 @@ declare class ManualSyncDoc extends ManualSyncTransport {
8
8
  readonly dsl: MedeoDsl;
9
9
  readonly editor: DslEditor;
10
10
  private constructor();
11
- static open(options: ManualSyncDocOptions): Promise<ManualSyncDoc>;
11
+ /** `uploadText` stores raw content the editor writes, such as a PhoneticScript's text, in Memota. */
12
+ static open(options: ManualSyncDocOptions & {
13
+ uploadText?: UploadText;
14
+ }): Promise<ManualSyncDoc>;
12
15
  snapshot(): {
13
16
  readonly "timeline-entities": {
14
17
  readonly [x: string]: {
@@ -73,6 +76,10 @@ declare class ManualSyncDoc extends ManualSyncTransport {
73
76
  readonly audioScriptId: string;
74
77
  readonly phonemeScript?: string | undefined;
75
78
  };
79
+ readonly system?: "memota" | undefined;
80
+ readonly key?: string | undefined;
81
+ readonly storageKey?: string | undefined;
82
+ readonly digest?: string | undefined;
76
83
  };
77
84
  };
78
85
  readonly "caption-entities": {
@@ -117,6 +124,7 @@ declare class ManualSyncDoc extends ManualSyncTransport {
117
124
  readonly [x: string]: {
118
125
  readonly entityId: string;
119
126
  readonly sourceId: string;
127
+ readonly sourceDigest?: string | undefined;
120
128
  };
121
129
  };
122
130
  readonly 'contain-relations': readonly {
@@ -158,9 +166,14 @@ declare class ManualSyncDoc extends ManualSyncTransport {
158
166
  type MengineDocSessionUpdateEvent = DocumentSessionUpdateEvent<MedeoDslSnapshot>;
159
167
  /** Default collaborative session: one DSL handle and one editor over the synchronized LoroDoc. */
160
168
  declare class MengineDocSession extends DocumentSession<MedeoDslSnapshot, DslEditor, MedeoDsl> {
161
- constructor(options: MengineDocSessionOptions);
169
+ /** `uploadText` stores raw content the editor writes, such as a PhoneticScript's text, in Memota. */
170
+ constructor(options: MengineDocSessionOptions & {
171
+ uploadText?: UploadText;
172
+ });
162
173
  get dsl(): MedeoDsl;
163
174
  projectVideoDraft(): VideoDraftProjection;
175
+ /** The document's AudioScripts with what says and shows them; read from the same snapshot as the VideoDraft. */
176
+ projectAudioScripts(): AudioScriptView[];
164
177
  }
165
178
  //#endregion
166
179
  export { MengineDocSessionUpdateEvent as n, ManualSyncDoc as r, MengineDocSession as t };
@@ -1,4 +1,4 @@
1
- import { $ as TrackRole, C as CaptionContent, L as FieldPatch, M as DslMutation, R as MedeoDslSnapshot, T as CaptionStyle, Z as TimeAnchor, c as VideoDraftInput, et as Voice, h as DslIdFactory, j as DslDiagnostic, o as VideoDraftContent, p as CommitOptions, q as TextEdit, w as CaptionSelection, z as Media } from "./video-draft-types-BfkIuW5f.js";
1
+ import { C as CaptionContent, J as TextEdit, K as StoredFile, L as FieldPatch, M as DslMutation, Q as TimeAnchor, R as MedeoDslSnapshot, T as CaptionStyle, c as VideoDraftInput, et as TrackRole, h as DslIdFactory, j as DslDiagnostic, o as VideoDraftContent, p as CommitOptions, tt as Voice, w as CaptionSelection, z as Media } from "./video-draft-types-Bq15tPBP.js";
2
2
  import { ContainerType, Cursor, LoroDoc, PeerID, TreeID } from "loro-crdt";
3
3
 
4
4
  //#region src/dsl/action-context.d.ts
@@ -476,11 +476,19 @@ declare const medeoDslLoroShape: RootSchemaType<{
476
476
  };
477
477
  'phonetic-script-entities': LoroMapSchemaWithCatchall<{}, LoroMapSchema<{
478
478
  phoneme: /*elided*/any;
479
+ system: /*elided*/any;
480
+ key: /*elided*/any;
481
+ storageKey: /*elided*/any;
482
+ digest: /*elided*/any;
479
483
  }> & {
480
484
  options: {};
481
485
  } & {
482
486
  catchall: <C extends SchemaType>(catchallSchema: C) => LoroMapSchemaWithCatchall<{
483
487
  phoneme: /*elided*/any;
488
+ system: /*elided*/any;
489
+ key: /*elided*/any;
490
+ storageKey: /*elided*/any;
491
+ digest: /*elided*/any;
484
492
  }, C>;
485
493
  }> & {
486
494
  options: {};
@@ -545,24 +553,18 @@ declare const medeoDslLoroShape: RootSchemaType<{
545
553
  readonly mergeableMapChildContainers: true;
546
554
  };
547
555
  };
548
- 'derived-from-relations': LoroMapSchemaWithCatchall<{}, LoroMapSchema<Record<string, StringSchemaType<string> & {
549
- options: {};
550
- } & {
551
- transform: <D>(def: TransformDefinition<string, D>) => StringSchemaType<string> & {
552
- options: {};
553
- transform: TransformDefinition<string, D>;
554
- };
555
- }>> & {
556
+ 'derived-from-relations': LoroMapSchemaWithCatchall<{}, LoroMapSchema<{
557
+ entityId: /*elided*/any;
558
+ sourceId: /*elided*/any;
559
+ sourceDigest: /*elided*/any;
560
+ }> & {
556
561
  options: {};
557
562
  } & {
558
- catchall: <C extends SchemaType>(catchallSchema: C) => LoroMapSchemaWithCatchall<Record<string, StringSchemaType<string> & {
559
- options: {};
560
- } & {
561
- transform: <D>(def: TransformDefinition<string, D>) => StringSchemaType<string> & {
562
- options: {};
563
- transform: TransformDefinition<string, D>;
564
- };
565
- }>, C>;
563
+ catchall: <C extends SchemaType>(catchallSchema: C) => LoroMapSchemaWithCatchall<{
564
+ entityId: /*elided*/any;
565
+ sourceId: /*elided*/any;
566
+ sourceDigest: /*elided*/any;
567
+ }, C>;
566
568
  }> & {
567
569
  options: {
568
570
  readonly mergeableMapChildContainers: true;
@@ -697,15 +699,31 @@ interface ApplyVoiceoverInput {
697
699
  }> & {
698
700
  kind: 'voiceover-recording';
699
701
  };
702
+ /**
703
+ * What the recording says: an existing AudioScript, a new one from `body`, or a PhoneticScript it
704
+ * was spoken from. A recording spoken from a PhoneticScript is derived-from it, and its captions
705
+ * select that variant's base script.
706
+ */
700
707
  script: {
701
708
  audioScriptId: string;
702
709
  body?: never;
710
+ phoneticScriptId?: never;
703
711
  } | {
704
712
  body: string;
705
713
  audioScriptId?: never;
714
+ phoneticScriptId?: never;
706
715
  defaultLanguage?: string;
716
+ } | {
717
+ phoneticScriptId: string;
718
+ audioScriptId?: never;
719
+ body?: never;
707
720
  };
708
721
  placement: ClipPlacement;
722
+ /**
723
+ * The digest of what the recording was synthesized from (D177): the PhoneticScript as it was
724
+ * read for synthesis. Absent, the source's digest as this voiceover leaves it is recorded.
725
+ */
726
+ sourceDigest?: string;
709
727
  volume?: number;
710
728
  voice?: Voice;
711
729
  /** Complete generated caption set for this use. Other uses of the recording are untouched. */
@@ -720,11 +738,17 @@ interface VoiceoverResult {
720
738
  }
721
739
  //#endregion
722
740
  //#region src/dsl/dsl-editor.d.ts
741
+ /**
742
+ * Stores raw content in Memota as a text file and returns the file's facts. The host owns the
743
+ * store; an entity with the Media File trait keeps the facts beside the content (D178).
744
+ */
745
+ type UploadText = (text: string) => Promise<StoredFile>;
723
746
  /** Business edits write DSL facts in one audited transaction; layout is derived on read. */
724
747
  declare class DslEditor {
725
748
  readonly dsl: MedeoDsl;
726
749
  private readonly idFactory;
727
- constructor(dsl: MedeoDsl, idFactory?: DslIdFactory);
750
+ private readonly uploadText?;
751
+ constructor(dsl: MedeoDsl, idFactory?: DslIdFactory, uploadText?: UploadText | undefined);
728
752
  createTrack(role: TrackRole, options?: CommitOptions): string;
729
753
  registerMedia(media: Media, options?: CommitOptions): string;
730
754
  addClips(input: AddDslClipsInput, options?: CommitOptions): string[];
@@ -770,6 +794,20 @@ declare class DslEditor {
770
794
  updateClips(updates: readonly DslClipUpdate[], options?: CommitOptions): void;
771
795
  patchCaptionStyle(captionIds: readonly string[], patch: FieldPatch<CaptionStyle>, options?: CommitOptions): void;
772
796
  applyVoiceover(input: ApplyVoiceoverInput, options?: CommitOptions): VoiceoverResult;
797
+ private voiceoverScriptId;
798
+ /**
799
+ * Write a PhoneticScript: create one for `audioScriptId`, or, given `phoneticScriptId`, replace its
800
+ * base and pronunciation together. A `phonemeScript` is stored as a Memota text file first, and
801
+ * the file's facts are written with it; an unchanged one keeps its file. Recordings already spoken
802
+ * from it keep their derived-from.
803
+ */
804
+ setPhoneticScript(input: {
805
+ phoneticScriptId?: string;
806
+ audioScriptId: string;
807
+ phonemeScript?: string;
808
+ }, options?: CommitOptions): Promise<string>;
809
+ /** The file holding `text`: the one the PhoneticScript keeps while its text is unchanged, else a new upload. */
810
+ private fileFor;
773
811
  setBgm(input: ClipSource & {
774
812
  trackId: string;
775
813
  clipId?: string;
@@ -828,6 +866,52 @@ interface VideoDraftProjection {
828
866
  /** A content read view, not an archive of authoring identities, rich-text marks or provenance. */
829
867
  declare function toVideoDraft(snapshot: MedeoDslSnapshot): VideoDraftProjection;
830
868
  //#endregion
869
+ //#region src/dsl/projection/audio-scripts.d.ts
870
+ /**
871
+ * An AudioScript with everything that says or shows it, read from the same snapshot as the
872
+ * VideoDraft. Speeches and captions come in playback order.
873
+ */
874
+ interface AudioScriptView {
875
+ id: string;
876
+ /** Its text, one segment per line. */
877
+ segments: {
878
+ text: string;
879
+ language?: string;
880
+ }[];
881
+ /** Media the script was read off (a transcript), through derived-from. */
882
+ sourceMediaIds: string[];
883
+ /** Its variants written for synthesis: the pronunciation the plain text cannot state, and its file's digest. */
884
+ phoneticScripts: {
885
+ id: string;
886
+ phonemeScript?: string;
887
+ digest?: string;
888
+ }[];
889
+ /** Speech Clips playing a recording of these words. */
890
+ speeches: {
891
+ clipId: string;
892
+ recordingId: string; /** The PhoneticScript the recording was spoken from; absent when it derives from the script directly. */
893
+ phoneticScriptId?: string;
894
+ voices: {
895
+ voiceId: string;
896
+ key: string;
897
+ name?: string;
898
+ }[];
899
+ /**
900
+ * Whether the recording was synthesized from its source as it is now: the digest its
901
+ * derived-from records equals the source's digest (D177). Absent when either has none.
902
+ */
903
+ applied?: boolean;
904
+ }[];
905
+ /** Caption Clips showing one of its segments. A Caption with its own text shows none. */
906
+ captions: {
907
+ clipId: string;
908
+ captionId: string;
909
+ segment: number;
910
+ }[];
911
+ }
912
+ /** Every AudioScript in the document with its PhoneticScripts, the Speech Clips saying it and the Caption Clips showing it. */
913
+ declare function toAudioScriptViews(snapshot: MedeoDslSnapshot): AudioScriptView[];
914
+ //#endregion
831
915
  //#region src/dsl/projection/from-video-draft.d.ts
832
916
  interface FromVideoDraftOptions extends CreateMedeoDslOptions {
833
917
  /** Complete physical media facts, keyed by their external system/key; no IO runs in the converter. */
@@ -841,4 +925,4 @@ interface ImportedVideoDraft {
841
925
  /** One-time import into a newly owned document; never reverse-diff a live collaborative document. */
842
926
  declare function fromVideoDraft(input: VideoDraftInput, options: FromVideoDraftOptions): ImportedVideoDraft;
843
927
  //#endregion
844
- export { AddDslClip as A, InvalidAtomic as C, MedeoDslDraft as D, timeAnchorCodec as E, ReplaceDslClipsInput as F, ClipPlacement as I, ClipSource as M, DslClipUpdate as N, MedeoDslLoroState as O, MoveDslClipsInput as P, documentFormat as S, isInvalidAtomic as T, MedeoDsl as _, toVideoDraft as a, UnsupportedDocumentFormatError as b, DslLayout as c, createInitialMedeoDsl as d, DslEditor as f, CreateMedeoDslOptions as g, VoiceoverResult as h, VideoDraftProjection as i, AddDslClipsInput as j, medeoDslLoroShape as k, DslProjectionError as l, VoiceoverCaptionInput as m, ImportedVideoDraft as n, resolveDslLayout as o, ApplyVoiceoverInput as p, fromVideoDraft as r, DslClipLayout as s, FromVideoDraftOptions as t, DslTrackLayout as u, DslAudit as v, captionContentCodec as w, assertDslDocument as x, DslTransaction as y };
928
+ export { MedeoDslDraft as A, UnsupportedDocumentFormatError as C, captionContentCodec as D, InvalidAtomic as E, ClipSource as F, DslClipUpdate as I, MoveDslClipsInput as L, medeoDslLoroShape as M, AddDslClip as N, isInvalidAtomic as O, AddDslClipsInput as P, ReplaceDslClipsInput as R, DslTransaction as S, documentFormat as T, VoiceoverCaptionInput as _, toAudioScriptViews as a, MedeoDsl as b, resolveDslLayout as c, DslProjectionError as d, DslTrackLayout as f, ApplyVoiceoverInput as g, UploadText as h, AudioScriptView as i, MedeoDslLoroState as j, timeAnchorCodec as k, DslClipLayout as l, DslEditor as m, ImportedVideoDraft as n, VideoDraftProjection as o, createInitialMedeoDsl as p, fromVideoDraft as r, toVideoDraft as s, FromVideoDraftOptions as t, DslLayout as u, VoiceoverResult as v, assertDslDocument as w, DslAudit as x, CreateMedeoDslOptions as y, ClipPlacement as z };
@@ -1,4 +1,4 @@
1
- import { j as DslDiagnostic, o as VideoDraftContent, p as CommitOptions } from "./video-draft-types-BfkIuW5f.js";
1
+ import { j as DslDiagnostic, o as VideoDraftContent, p as CommitOptions } from "./video-draft-types-Bq15tPBP.js";
2
2
  import { LoroDoc, PeerID, VersionVector } from "loro-crdt";
3
3
  import { DocState, LocalSaveState } from "@mengine/sync";
4
4
  import { BaseDocStorage, Connection, DocDiff, DocPushReceipt, DocSnapshotRecord, DocStorage, DocStorageOptions, DocUpdate, DocUpdateRecord } from "@mengine/storage";
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { $ as TrackRole, A as DeepReadonly, B as RelationMutation, C as CaptionContent, D as Clip, E as CaptionText, F as EntityTables, G as RichTextSnapshot, H as RelationTables, I as EntityValues, J as TextMark, K as TextDelta, L as FieldPatch, M as DslMutation, N as EntityMutation, O as ContainMutation, P as EntityTable, Q as Track, R as MedeoDslSnapshot, S as Caption, T as CaptionStyle, U as RelationValues, V as RelationTable, W as ResourceSystem, X as TextRun, Y as TextMutation, Z as TimeAnchor, _ as defaultIdFactory, a as VideoDraftCaptionStyle, b as tupleHash, c as VideoDraftInput, d as VideoDraftTrack, et as Voice, f as VideoDraftTrackItem, g as EntityIdKind, h as DslIdFactory, i as VideoDraft, j as DslDiagnostic, k as ContainNode, l as VideoDraftPartUnion, m as OpActor, n as DEFAULT_UNIT_TIME_MS, o as VideoDraftContent, p as CommitOptions, q as TextEdit, r as VideoCreationSettings, s as VideoDraftContentPartUnion, t as CaptionDisplayCue, u as VideoDraftTimeline, v as relationId, w as CaptionSelection, x as AudioScript, y as resourceId, z as Media } from "./video-draft-types-BfkIuW5f.js";
2
- import { A as AddDslClip, C as InvalidAtomic, D as MedeoDslDraft, E as timeAnchorCodec, F as ReplaceDslClipsInput, I as ClipPlacement, M as ClipSource, N as DslClipUpdate, O as MedeoDslLoroState, P as MoveDslClipsInput, S as documentFormat, T as isInvalidAtomic, _ as MedeoDsl, a as toVideoDraft, b as UnsupportedDocumentFormatError, c as DslLayout, d as createInitialMedeoDsl, f as DslEditor, g as CreateMedeoDslOptions, h as VoiceoverResult, i as VideoDraftProjection, j as AddDslClipsInput, k as medeoDslLoroShape, l as DslProjectionError, m as VoiceoverCaptionInput, n as ImportedVideoDraft, o as resolveDslLayout, p as ApplyVoiceoverInput, r as fromVideoDraft, s as DslClipLayout, t as FromVideoDraftOptions, u as DslTrackLayout, v as DslAudit, w as captionContentCodec, x as assertDslDocument, y as DslTransaction } from "./index-DP9FG0z_.js";
3
- import { A as MenginePushRejectedError, B as MengineSyncResponse, C as PushResult, D as MengineHttpClient, E as readMengineEventStream, F as MenginePushResponse, H as base64ToBytes, I as MenginePushUpdateResponse, L as MengineRejectedResponse, M as MengineAuditResponse, N as MengineDocumentVersion, O as MengineHttpClientOptions, P as MengineDraftResponse, R as MengineSnapshotResponse, S as PullResult, T as MengineEventStreamOptions, U as bytesToBase64, V as MengineUpdateMeta, a as MengineDocSessionOptions, b as DocVersionMark, c as WaitForLocalSaveOptions, d as MengineUndoState, f as MedeoHttpDocStorage, g as ManualSyncDocOptions, h as PushOutcomeKind, i as MengineAckFailedError, j as MengineAuditEntry, k as MengineHttpRequestError, l as WaitForServerAckOptions, m as PushOutcome, o as MengineDocSyncState, p as MedeoHttpDocStorageOptions, s as MengineLocalSaveState, t as MemoryDocStorage, u as DocStorageLike, v as decodeDocVersionMark, w as PushResultKind, x as PullFailureReason, y as encodeDocVersionMark, z as MengineSseUpdateEvent } from "./index-CwG4lYKp.js";
4
- import { n as MengineDocSessionUpdateEvent, r as ManualSyncDoc, t as MengineDocSession } from "./index-W1eHhVus.js";
5
- export { type AddDslClip, type AddDslClipsInput, type ApplyVoiceoverInput, type AudioScript, type Caption, type CaptionContent, type CaptionDisplayCue, type CaptionSelection, type CaptionStyle, type CaptionText, type Clip, type ClipPlacement, type ClipSource, type CommitOptions, type ContainMutation, type ContainNode, type CreateMedeoDslOptions, DEFAULT_UNIT_TIME_MS, type DeepReadonly, type DocStorageLike, type DocVersionMark, type DslAudit, type DslClipLayout, type DslClipUpdate, type DslDiagnostic, DslEditor, type DslIdFactory, type DslLayout, type DslMutation, DslProjectionError, type DslTrackLayout, type DslTransaction, type EntityIdKind, type EntityMutation, type EntityTable, type EntityTables, type EntityValues, type FieldPatch, type FromVideoDraftOptions, type ImportedVideoDraft, type InvalidAtomic, ManualSyncDoc, type ManualSyncDocOptions, MedeoDsl, type MedeoDslDraft, type MedeoDslLoroState, type MedeoDslSnapshot, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type Media, MemoryDocStorage, MengineAckFailedError, type MengineAuditEntry, type MengineAuditResponse, MengineDocSession, type MengineDocSessionOptions, type MengineDocSessionUpdateEvent, type MengineDocSyncState, type MengineDocumentVersion, type MengineDraftResponse, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, type MengineLocalSaveState, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUndoState, type MengineUpdateMeta, type MoveDslClipsInput, type OpActor, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, type RelationMutation, type RelationTable, type RelationTables, type RelationValues, type ReplaceDslClipsInput, type ResourceSystem, type RichTextSnapshot, type TextDelta, type TextEdit, type TextMark, type TextMutation, type TextRun, type TimeAnchor, type Track, type TrackRole, UnsupportedDocumentFormatError, type VideoCreationSettings, type VideoDraft, type VideoDraftCaptionStyle, type VideoDraftContent, type VideoDraftContentPartUnion, type VideoDraftInput, type VideoDraftPartUnion, type VideoDraftProjection, type VideoDraftTimeline, type VideoDraftTrack, type VideoDraftTrackItem, type Voice, type VoiceoverCaptionInput, type VoiceoverResult, type WaitForLocalSaveOptions, type WaitForServerAckOptions, assertDslDocument, base64ToBytes, bytesToBase64, captionContentCodec, createInitialMedeoDsl, decodeDocVersionMark, defaultIdFactory, documentFormat, encodeDocVersionMark, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, readMengineEventStream, relationId, resolveDslLayout, resourceId, timeAnchorCodec, toVideoDraft, tupleHash };
1
+ import { $ as Track, A as DeepReadonly, B as RelationMutation, C as CaptionContent, D as Clip, E as CaptionText, F as EntityTables, G as RichTextSnapshot, H as RelationTables, I as EntityValues, J as TextEdit, K as StoredFile, L as FieldPatch, M as DslMutation, N as EntityMutation, O as ContainMutation, P as EntityTable, Q as TimeAnchor, R as MedeoDslSnapshot, S as Caption, T as CaptionStyle, U as RelationValues, V as RelationTable, W as ResourceSystem, X as TextMutation, Y as TextMark, Z as TextRun, _ as defaultIdFactory, a as VideoDraftCaptionStyle, b as tupleHash, c as VideoDraftInput, d as VideoDraftTrack, et as TrackRole, f as VideoDraftTrackItem, g as EntityIdKind, h as DslIdFactory, i as VideoDraft, j as DslDiagnostic, k as ContainNode, l as VideoDraftPartUnion, m as OpActor, n as DEFAULT_UNIT_TIME_MS, o as VideoDraftContent, p as CommitOptions, q as TextDelta, r as VideoCreationSettings, s as VideoDraftContentPartUnion, t as CaptionDisplayCue, tt as Voice, u as VideoDraftTimeline, v as relationId, w as CaptionSelection, x as AudioScript, y as resourceId, z as Media } from "./video-draft-types-Bq15tPBP.js";
2
+ import { A as MedeoDslDraft, C as UnsupportedDocumentFormatError, D as captionContentCodec, E as InvalidAtomic, F as ClipSource, I as DslClipUpdate, L as MoveDslClipsInput, M as medeoDslLoroShape, N as AddDslClip, O as isInvalidAtomic, P as AddDslClipsInput, R as ReplaceDslClipsInput, S as DslTransaction, T as documentFormat, _ as VoiceoverCaptionInput, a as toAudioScriptViews, b as MedeoDsl, c as resolveDslLayout, d as DslProjectionError, f as DslTrackLayout, g as ApplyVoiceoverInput, h as UploadText, i as AudioScriptView, j as MedeoDslLoroState, k as timeAnchorCodec, l as DslClipLayout, m as DslEditor, n as ImportedVideoDraft, o as VideoDraftProjection, p as createInitialMedeoDsl, r as fromVideoDraft, s as toVideoDraft, t as FromVideoDraftOptions, u as DslLayout, v as VoiceoverResult, w as assertDslDocument, x as DslAudit, y as CreateMedeoDslOptions, z as ClipPlacement } from "./index-DHcMMn2M.js";
3
+ import { A as MenginePushRejectedError, B as MengineSyncResponse, C as PushResult, D as MengineHttpClient, E as readMengineEventStream, F as MenginePushResponse, H as base64ToBytes, I as MenginePushUpdateResponse, L as MengineRejectedResponse, M as MengineAuditResponse, N as MengineDocumentVersion, O as MengineHttpClientOptions, P as MengineDraftResponse, R as MengineSnapshotResponse, S as PullResult, T as MengineEventStreamOptions, U as bytesToBase64, V as MengineUpdateMeta, a as MengineDocSessionOptions, b as DocVersionMark, c as WaitForLocalSaveOptions, d as MengineUndoState, f as MedeoHttpDocStorage, g as ManualSyncDocOptions, h as PushOutcomeKind, i as MengineAckFailedError, j as MengineAuditEntry, k as MengineHttpRequestError, l as WaitForServerAckOptions, m as PushOutcome, o as MengineDocSyncState, p as MedeoHttpDocStorageOptions, s as MengineLocalSaveState, t as MemoryDocStorage, u as DocStorageLike, v as decodeDocVersionMark, w as PushResultKind, x as PullFailureReason, y as encodeDocVersionMark, z as MengineSseUpdateEvent } from "./index-Dpl4bT94.js";
4
+ import { n as MengineDocSessionUpdateEvent, r as ManualSyncDoc, t as MengineDocSession } from "./index-Cx5DojM1.js";
5
+ export { type AddDslClip, type AddDslClipsInput, type ApplyVoiceoverInput, type AudioScript, type AudioScriptView, type Caption, type CaptionContent, type CaptionDisplayCue, type CaptionSelection, type CaptionStyle, type CaptionText, type Clip, type ClipPlacement, type ClipSource, type CommitOptions, type ContainMutation, type ContainNode, type CreateMedeoDslOptions, DEFAULT_UNIT_TIME_MS, type DeepReadonly, type DocStorageLike, type DocVersionMark, type DslAudit, type DslClipLayout, type DslClipUpdate, type DslDiagnostic, DslEditor, type DslIdFactory, type DslLayout, type DslMutation, DslProjectionError, type DslTrackLayout, type DslTransaction, type EntityIdKind, type EntityMutation, type EntityTable, type EntityTables, type EntityValues, type FieldPatch, type FromVideoDraftOptions, type ImportedVideoDraft, type InvalidAtomic, ManualSyncDoc, type ManualSyncDocOptions, MedeoDsl, type MedeoDslDraft, type MedeoDslLoroState, type MedeoDslSnapshot, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type Media, MemoryDocStorage, MengineAckFailedError, type MengineAuditEntry, type MengineAuditResponse, MengineDocSession, type MengineDocSessionOptions, type MengineDocSessionUpdateEvent, type MengineDocSyncState, type MengineDocumentVersion, type MengineDraftResponse, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, type MengineLocalSaveState, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUndoState, type MengineUpdateMeta, type MoveDslClipsInput, type OpActor, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, type RelationMutation, type RelationTable, type RelationTables, type RelationValues, type ReplaceDslClipsInput, type ResourceSystem, type RichTextSnapshot, type StoredFile, type TextDelta, type TextEdit, type TextMark, type TextMutation, type TextRun, type TimeAnchor, type Track, type TrackRole, UnsupportedDocumentFormatError, type UploadText, type VideoCreationSettings, type VideoDraft, type VideoDraftCaptionStyle, type VideoDraftContent, type VideoDraftContentPartUnion, type VideoDraftInput, type VideoDraftPartUnion, type VideoDraftProjection, type VideoDraftTimeline, type VideoDraftTrack, type VideoDraftTrackItem, type Voice, type VoiceoverCaptionInput, type VoiceoverResult, type WaitForLocalSaveOptions, type WaitForServerAckOptions, assertDslDocument, base64ToBytes, bytesToBase64, captionContentCodec, createInitialMedeoDsl, decodeDocVersionMark, defaultIdFactory, documentFormat, encodeDocVersionMark, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, readMengineEventStream, 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
- 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-DvPeam87.js";
4
- import { a as MedeoDsl, i as DslEditor, n as toVideoDraft, o as resolveDslLayout, r as createInitialMedeoDsl, s as DslProjectionError, t as fromVideoDraft } from "./dsl-BCcld0Ca.js";
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-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";
@@ -10,14 +10,15 @@ import { DisposableSet, EventBus } from "@mengine/utils";
10
10
  var ManualSyncDoc = class ManualSyncDoc extends ManualSyncTransport {
11
11
  dsl;
12
12
  editor;
13
- constructor(client, doc, watermark) {
13
+ constructor(client, doc, watermark, uploadText) {
14
14
  super(client, doc, watermark);
15
15
  assertDslDocument(doc);
16
16
  this.dsl = new MedeoDsl(doc);
17
- this.editor = new DslEditor(this.dsl);
17
+ this.editor = new DslEditor(this.dsl, void 0, uploadText);
18
18
  }
19
+ /** `uploadText` stores raw content the editor writes, such as a PhoneticScript's text, in Memota. */
19
20
  static open(options) {
20
- return openManualDocument(options, (doc, watermark) => new ManualSyncDoc(options.client, doc, watermark));
21
+ return openManualDocument(options, (doc, watermark) => new ManualSyncDoc(options.client, doc, watermark, options.uploadText));
21
22
  }
22
23
  snapshot() {
23
24
  this.assertActive();
@@ -623,6 +624,7 @@ function serverCovers(serverVV, target) {
623
624
  //#region src/session/mengine-doc-session.ts
624
625
  /** Default collaborative session: one DSL handle and one editor over the synchronized LoroDoc. */
625
626
  var MengineDocSession = class extends DocumentSession {
627
+ /** `uploadText` stores raw content the editor writes, such as a PhoneticScript's text, in Memota. */
626
628
  constructor(options) {
627
629
  super(options, (doc, guard) => {
628
630
  assertDslDocument(doc);
@@ -630,7 +632,7 @@ var MengineDocSession = class extends DocumentSession {
630
632
  return {
631
633
  doc,
632
634
  document: dsl,
633
- editor: new DslEditor(dsl),
635
+ editor: new DslEditor(dsl, void 0, options.uploadText),
634
636
  snapshot: () => dsl.getSnapshot(),
635
637
  subscribe: (listener) => dsl.subscribe(listener),
636
638
  dispose: () => dsl.dispose()
@@ -643,6 +645,10 @@ var MengineDocSession = class extends DocumentSession {
643
645
  projectVideoDraft() {
644
646
  return toVideoDraft(this.snapshot());
645
647
  }
648
+ /** The document's AudioScripts with what says and shows them; read from the same snapshot as the VideoDraft. */
649
+ projectAudioScripts() {
650
+ return toAudioScriptViews(this.snapshot());
651
+ }
646
652
  };
647
653
  //#endregion
648
- export { DEFAULT_UNIT_TIME_MS, DslEditor, DslProjectionError, ManualSyncDoc, MedeoDsl, MedeoHttpDocStorage, MemoryDocStorage, MengineAckFailedError, MengineDocSession, MengineHttpClient, MengineHttpRequestError, MenginePushRejectedError, UnsupportedDocumentFormatError, assertDslDocument, base64ToBytes, bytesToBase64, captionContentCodec, createInitialMedeoDsl, decodeDocVersionMark, defaultIdFactory, documentFormat, encodeDocVersionMark, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, readMengineEventStream, relationId, resolveDslLayout, resourceId, timeAnchorCodec, toVideoDraft, tupleHash };
654
+ export { DEFAULT_UNIT_TIME_MS, DslEditor, DslProjectionError, ManualSyncDoc, MedeoDsl, MedeoHttpDocStorage, MemoryDocStorage, MengineAckFailedError, MengineDocSession, MengineHttpClient, MengineHttpRequestError, MenginePushRejectedError, UnsupportedDocumentFormatError, assertDslDocument, base64ToBytes, bytesToBase64, captionContentCodec, createInitialMedeoDsl, decodeDocVersionMark, defaultIdFactory, documentFormat, encodeDocVersionMark, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, readMengineEventStream, relationId, resolveDslLayout, resourceId, timeAnchorCodec, toAudioScriptViews, toVideoDraft, tupleHash };
package/dist/legacy.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { i as VideoDraft, l as VideoDraftPartUnion, o as VideoDraftContent, p as CommitOptions, t as CaptionDisplayCue } from "./video-draft-types-BfkIuW5f.js";
2
- import { A as MenginePushRejectedError, B as MengineSyncResponse, C as PushResult, D as MengineHttpClient, E as readMengineEventStream, F as MenginePushResponse, H as base64ToBytes, I as MenginePushUpdateResponse, L as MengineRejectedResponse, M as MengineAuditResponse, N as MengineDocumentVersion, O as MengineHttpClientOptions, P as MengineDraftResponse, R as MengineSnapshotResponse, S as PullResult, T as MengineEventStreamOptions, U as bytesToBase64, V as MengineUpdateMeta, _ as ManualSyncTransport, a as MengineDocSessionOptions, b as DocVersionMark, d as MengineUndoState, f as MedeoHttpDocStorage, g as ManualSyncDocOptions, h as PushOutcomeKind, j as MengineAuditEntry, k as MengineHttpRequestError, l as WaitForServerAckOptions, m as PushOutcome, o as MengineDocSyncState, p as MedeoHttpDocStorageOptions, t as MemoryDocStorage, u as DocStorageLike, v as decodeDocVersionMark, w as PushResultKind, x as PullFailureReason, y as encodeDocVersionMark, z as MengineSseUpdateEvent } from "./index-CwG4lYKp.js";
1
+ import { i as VideoDraft, l as VideoDraftPartUnion, o as VideoDraftContent, p as CommitOptions, t as CaptionDisplayCue } from "./video-draft-types-Bq15tPBP.js";
2
+ import { A as MenginePushRejectedError, B as MengineSyncResponse, C as PushResult, D as MengineHttpClient, E as readMengineEventStream, F as MenginePushResponse, H as base64ToBytes, I as MenginePushUpdateResponse, L as MengineRejectedResponse, M as MengineAuditResponse, N as MengineDocumentVersion, O as MengineHttpClientOptions, P as MengineDraftResponse, R as MengineSnapshotResponse, S as PullResult, T as MengineEventStreamOptions, U as bytesToBase64, V as MengineUpdateMeta, _ as ManualSyncTransport, a as MengineDocSessionOptions, b as DocVersionMark, d as MengineUndoState, f as MedeoHttpDocStorage, g as ManualSyncDocOptions, h as PushOutcomeKind, j as MengineAuditEntry, k as MengineHttpRequestError, l as WaitForServerAckOptions, m as PushOutcome, o as MengineDocSyncState, p as MedeoHttpDocStorageOptions, t as MemoryDocStorage, u as DocStorageLike, v as decodeDocVersionMark, w as PushResultKind, x as PullFailureReason, y as encodeDocVersionMark, z as MengineSseUpdateEvent } from "./index-Dpl4bT94.js";
3
3
  import { LoroDoc, PeerID } from "loro-crdt";
4
4
 
5
5
  //#region ../medeo-dsl/depreacted/sandbox.d.ts
package/dist/legacy.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as bytesToBase64, t as base64ToBytes } from "./base64-D-jd-dr5.js";
2
2
  import { 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
- import { a as documentFormat, r as UnsupportedDocumentFormatError, t as DEFAULT_UNIT_TIME_MS } from "./video-draft-types-DvPeam87.js";
3
+ import { a as documentFormat, r as UnsupportedDocumentFormatError, t as DEFAULT_UNIT_TIME_MS } from "./video-draft-types-Ce8NDenQ.js";
4
4
  import { u as volumeSchema } from "./shared-iWnU2osE.js";
5
5
  import { sha256 } from "@noble/hashes/sha2.js";
6
6
  import { LoroDoc, LoroMap, LoroMovableList, LoroText, UndoManager } from "loro-crdt";
package/dist/testing.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { i as VideoDraft } from "./video-draft-types-BfkIuW5f.js";
2
- import { _ as MedeoDsl } from "./index-DP9FG0z_.js";
1
+ import { i as VideoDraft } from "./video-draft-types-Bq15tPBP.js";
2
+ import { b as MedeoDsl } from "./index-DHcMMn2M.js";
3
3
  import { LoroDoc } from "loro-crdt";
4
4
 
5
5
  //#region src/testing/in-memory-mengine-server.d.ts
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
- import { a as documentFormat, i as assertDslDocument } from "./video-draft-types-DvPeam87.js";
3
- import { a as MedeoDsl, i as DslEditor, n as toVideoDraft, r as createInitialMedeoDsl } from "./dsl-BCcld0Ca.js";
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-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
@@ -90,8 +90,19 @@ interface Phoneme {
90
90
  /** One whole script in the target TTS vocabulary, such as a `<speak>` document. */
91
91
  phonemeScript?: string;
92
92
  }
93
- /** A variant of an AudioScript: the script it reads, plus how to pronounce it. */
94
- interface PhoneticScript {
93
+ /** A file Memota stored from raw content: how a Media File entity names it, and its digest. */
94
+ interface StoredFile {
95
+ system: 'memota';
96
+ key: string;
97
+ storageKey?: string;
98
+ digest: string;
99
+ }
100
+ /**
101
+ * A variant of an AudioScript: the script it reads, plus how to pronounce it. It has the Media File
102
+ * trait (D178): its `phonemeScript` is raw content, stored in Memota as a text file whenever it is
103
+ * written, and the file's facts are kept beside it. Without a `phonemeScript` it has no file.
104
+ */
105
+ interface PhoneticScript extends Partial<StoredFile> {
95
106
  phoneme: Phoneme;
96
107
  }
97
108
  interface Voice {
@@ -116,9 +127,14 @@ interface RelationValues {
116
127
  recordingId: string;
117
128
  voiceId: string;
118
129
  };
130
+ /**
131
+ * `sourceDigest`: the source's digest when the product was made from it (D177). A product whose
132
+ * source's digest differs now was made from content the source no longer has.
133
+ */
119
134
  'derived-from-relations': {
120
135
  entityId: string;
121
136
  sourceId: string;
137
+ sourceDigest?: string;
122
138
  };
123
139
  }
124
140
  type EntityTable = keyof EntityValues;
@@ -802,4 +818,4 @@ type VideoDraftContent = Pick<VideoDraft, 'timeline' | 'main_track' | 'above_mai
802
818
  type VideoDraftInput = Pick<VideoDraft, keyof VideoDraftContent>;
803
819
  declare const DEFAULT_UNIT_TIME_MS = 33.333;
804
820
  //#endregion
805
- export { TrackRole as $, DeepReadonly as A, RelationMutation as B, CaptionContent as C, Clip as D, CaptionText as E, EntityTables as F, RichTextSnapshot as G, RelationTables as H, EntityValues as I, TextMark as J, TextDelta as K, FieldPatch as L, DslMutation as M, EntityMutation as N, ContainMutation as O, EntityTable as P, Track$1 as Q, MedeoDslSnapshot as R, Caption as S, CaptionStyle$1 as T, RelationValues as U, RelationTable as V, ResourceSystem as W, TextRun as X, TextMutation as Y, TimeAnchor as Z, defaultIdFactory as _, VideoDraftCaptionStyle as a, tupleHash as b, VideoDraftInput as c, VideoDraftTrack as d, Voice as et, VideoDraftTrackItem as f, EntityIdKind as g, DslIdFactory as h, VideoDraft as i, DslDiagnostic as j, ContainNode as k, VideoDraftPartUnion as l, OpActor as m, DEFAULT_UNIT_TIME_MS as n, VideoDraftContent as o, CommitOptions as p, TextEdit as q, VideoCreationSettings as r, VideoDraftContentPartUnion as s, CaptionDisplayCue as t, VideoDraftTimeline as u, relationId as v, CaptionSelection as w, AudioScript as x, resourceId as y, Media as z };
821
+ export { Track$1 as $, DeepReadonly as A, RelationMutation as B, CaptionContent as C, Clip as D, CaptionText as E, EntityTables as F, RichTextSnapshot as G, RelationTables as H, EntityValues as I, TextEdit as J, StoredFile as K, FieldPatch as L, DslMutation as M, EntityMutation as N, ContainMutation as O, EntityTable as P, TimeAnchor as Q, MedeoDslSnapshot as R, Caption as S, CaptionStyle$1 as T, RelationValues as U, RelationTable as V, ResourceSystem as W, TextMutation as X, TextMark as Y, TextRun as Z, defaultIdFactory as _, VideoDraftCaptionStyle as a, tupleHash as b, VideoDraftInput as c, VideoDraftTrack as d, TrackRole as et, VideoDraftTrackItem as f, EntityIdKind as g, DslIdFactory as h, VideoDraft as i, DslDiagnostic as j, ContainNode as k, VideoDraftPartUnion as l, OpActor as m, DEFAULT_UNIT_TIME_MS as n, VideoDraftContent as o, CommitOptions as p, TextDelta as q, VideoCreationSettings as r, VideoDraftContentPartUnion as s, CaptionDisplayCue as t, Voice as tt, VideoDraftTimeline as u, relationId as v, CaptionSelection as w, AudioScript as x, resourceId as y, Media as z };
@@ -173,7 +173,13 @@ const entityFields = {
173
173
  body: required(string),
174
174
  defaultLanguage: optional$1(validLanguage)
175
175
  },
176
- "phonetic-script-entities": { phoneme: required(object(phonemeFields)) },
176
+ "phonetic-script-entities": {
177
+ phoneme: required(object(phonemeFields)),
178
+ system: optional$1(oneOf("memota")),
179
+ key: optional$1(nonempty),
180
+ storageKey: optional$1(nonempty),
181
+ digest: optional$1(nonempty)
182
+ },
177
183
  "caption-entities": {
178
184
  selection: optional$1(object(captionContentFields)),
179
185
  text: optional$1(string),
@@ -202,12 +208,30 @@ const relationFields = {
202
208
  },
203
209
  "derived-from-relations": {
204
210
  entityId: required(id),
205
- sourceId: required(id)
211
+ sourceId: required(id),
212
+ sourceDigest: optional$1(nonempty)
206
213
  }
207
214
  };
208
215
  const relationTables = Object.keys(relationFields);
216
+ const fileFields = [
217
+ "system",
218
+ "key",
219
+ "storageKey",
220
+ "digest"
221
+ ];
222
+ const phonemeScriptOf = (row) => isRecord(row.phoneme) ? row.phoneme.phonemeScript : void 0;
223
+ /**
224
+ * A PhoneticScript's phonemeScript is raw content stored as its file when written (D178): with one,
225
+ * the row names that file by system and key and states its digest; without one it has no file.
226
+ */
227
+ function assertPhoneticFile(row) {
228
+ if (phonemeScriptOf(row) === void 0) {
229
+ if (fileFields.some((field) => row[field] !== void 0)) throw new Error("A PhoneticScript without text has no file");
230
+ } else if (row.system === void 0 || row.key === void 0 || row.digest === void 0) throw new Error("A PhoneticScript stores its phonemeScript as a file: name it by system and key with its digest");
231
+ }
209
232
  function assertEntity(table, value) {
210
233
  checkFields(value, entityFields[table]);
234
+ if (table === "phonetic-script-entities") assertPhoneticFile(value);
211
235
  if (table === "media-entities") {
212
236
  if (value.kind === "image" && value.durationMs !== void 0) throw new Error("Image has no intrinsic duration");
213
237
  if (value.kind !== "image" && !positive(value.durationMs)) throw new Error("Finite media requires durationMs");
@@ -225,6 +249,10 @@ function assertEntityPatch(table, patch, current) {
225
249
  const field = entityFields[table][key];
226
250
  if (!field || !field.optional && next[key] === void 0 || next[key] !== void 0 && !field.check(next[key])) throw new Error(`Invalid patch field: ${key}`);
227
251
  }
252
+ if (table === "phonetic-script-entities" && ["phoneme", ...fileFields].some((field) => Object.hasOwn(patch, field))) {
253
+ assertPhoneticFile(next);
254
+ if (phonemeScriptOf(next) !== phonemeScriptOf(current) && next.digest !== void 0 && next.digest === current.digest) throw new Error("A rewritten phonemeScript is stored again: write its new file");
255
+ }
228
256
  if (table === "media-entities" || table === "voice-entities") {
229
257
  for (const key of [
230
258
  "system",
@@ -1358,7 +1386,13 @@ const medeoDslLoroShape = schema({
1358
1386
  body: schema.LoroText(),
1359
1387
  defaultLanguage: schema.String(optional)
1360
1388
  })),
1361
- "phonetic-script-entities": schema.LoroMapRecord(schema.LoroMap({ phoneme: atomicValue(phonemeCodec) })),
1389
+ "phonetic-script-entities": schema.LoroMapRecord(schema.LoroMap({
1390
+ phoneme: atomicValue(phonemeCodec),
1391
+ system: schema.String(optional),
1392
+ key: schema.String(optional),
1393
+ storageKey: schema.String(optional),
1394
+ digest: schema.String(optional)
1395
+ })),
1362
1396
  "caption-entities": schema.LoroMapRecord(schema.LoroMap({
1363
1397
  selection: optionalAtomicValue(captionContentCodec),
1364
1398
  text: schema.LoroText(optional),
@@ -1388,7 +1422,11 @@ const medeoDslLoroShape = schema({
1388
1422
  }), mergeable),
1389
1423
  "contain-relations": schema.LoroTree(schema.LoroMap({ entityId: schema.String() })),
1390
1424
  "voice-timbre-relations": relation(["recordingId", "voiceId"]),
1391
- "derived-from-relations": relation(["entityId", "sourceId"])
1425
+ "derived-from-relations": schema.LoroMapRecord(schema.LoroMap({
1426
+ entityId: schema.String(),
1427
+ sourceId: schema.String(),
1428
+ sourceDigest: schema.String(optional)
1429
+ }), mergeable)
1392
1430
  });
1393
1431
  //#endregion
1394
1432
  //#region ../medeo-dsl/src/schema/document-format.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mengine/medeo-client",
3
- "version": "2.1.1-dsl.4",
3
+ "version": "2.1.1-dsl.6",
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.4",
33
- "@mengine/sync": "2.1.1-dsl.4",
34
- "@mengine/utils": "2.1.1-dsl.4"
32
+ "@mengine/storage": "2.1.1-dsl.6",
33
+ "@mengine/utils": "2.1.1-dsl.6",
34
+ "@mengine/sync": "2.1.1-dsl.6"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/node": "^25.9.1",
@@ -42,8 +42,8 @@
42
42
  "typescript": "^6.0.3",
43
43
  "vite-plugin-wasm": "^3.6.0",
44
44
  "vite-plus": "^0.1.23",
45
- "@mengine/idl-codegen": "0.0.0",
46
- "@mengine/medeo-dsl": "0.0.0"
45
+ "@mengine/medeo-dsl": "0.0.0",
46
+ "@mengine/idl-codegen": "0.0.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "loro-crdt": "^1.16.1"