@mengine/medeo-client 1.3.1-alpha.10 → 1.3.1-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/{document-BxWxPFTj.js → document-CF-q_mRy.js} +16 -19
- package/dist/index.d.ts +5 -3
- package/dist/index.js +7 -8
- package/dist/testing.js +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ boundary already fails rows whose media variants lack `external` or carry a
|
|
|
44
44
|
media is an explicit caller decision, and no implicit historical merge or
|
|
45
45
|
identity rewriting occurs. The
|
|
46
46
|
compatibility reader reads physical facts directly from the media variant;
|
|
47
|
-
Caption text is assembled from its required AudioScript composition
|
|
47
|
+
Caption text is assembled from its required AudioScript composition. The host may associate Caption with a real text Asset through `physical-asset`, keyed by Caption identity; the sandbox does not manage Assets. The association is optional and does not replace composition. Editing inherited text through Caption advances the AudioScript version and its base reference, preserving the Caption ID unless its own fields change.
|
|
48
48
|
|
|
49
49
|
`SequenceMarker` owns source/target ranges, duration, and time remapping. `Clip`
|
|
50
50
|
owns clip properties such as volume; `Track` owns track properties. References
|
|
@@ -80,7 +80,7 @@ with `assembleCaptionContent` or `assemblePhoneticScriptContent`. Broken composi
|
|
|
80
80
|
fails explicitly. Same-name fields from different bases are rejected even for equal values and even if the variant declares that field. After base fields are unambiguous, explicit own fields may override them without mutating the bases. Recorded Audio/Video/Voice can be the ASR source via
|
|
81
81
|
`audio-script-source`, without creating a synthesis variant.
|
|
82
82
|
|
|
83
|
-
`insertCaptionClip` requires `baseEntityIds` and `selections`. Each selection
|
|
83
|
+
`insertCaptionClip` requires `baseEntityIds` and `selections`; its optional `captionEntityId` preserves a generation-provided business identity independently of `captionClipEntityId`. Each selection
|
|
84
84
|
names a source `segmentId` and optionally a half-open Unicode code-point
|
|
85
85
|
`textRange: {start, end}`. This permits display re-segmentation without rewriting
|
|
86
86
|
the original script. `upsertVoiceoverTake` requires the real
|
|
@@ -1784,9 +1784,8 @@ function entityToRow(entity) {
|
|
|
1784
1784
|
//#region ../medeo-dsl/src/invariants.ts
|
|
1785
1785
|
/**
|
|
1786
1786
|
* Media variants own their Asset identity directly: a `physical-asset`
|
|
1787
|
-
* Relation may not bind them. Caption
|
|
1788
|
-
*
|
|
1789
|
-
* open for future physical pipeline semantics.
|
|
1787
|
+
* Relation may not bind them. Caption may associate with a physical text Asset
|
|
1788
|
+
* independently of its AudioScript composition.
|
|
1790
1789
|
*/
|
|
1791
1790
|
function validateMediaAssetIdentity(entity, index) {
|
|
1792
1791
|
return [...index.relationsOf(entity)].filter((relation) => relation.kind === "physical-asset").map(() => ({
|
|
@@ -1945,11 +1944,6 @@ function validatePhoneticComposition(phonetic, index, entities = []) {
|
|
|
1945
1944
|
}
|
|
1946
1945
|
function validateVariantComposition(variant, index, entities, kind) {
|
|
1947
1946
|
const issues = [];
|
|
1948
|
-
if (kind === "caption" && ofKind([...index.relationsOf(variant)], "physical-asset").length > 0) issues.push({
|
|
1949
|
-
code: "caption_physical_asset_forbidden",
|
|
1950
|
-
entityId: variant.entityId,
|
|
1951
|
-
message: "Caption text is composed from its AudioScript; Caption must not bind a Physical Asset"
|
|
1952
|
-
});
|
|
1953
1947
|
const rows = {
|
|
1954
1948
|
entities: collectRelatedEntities([...entities, variant], index).entities.map((ref) => entityToRow(ref.current())),
|
|
1955
1949
|
relations: []
|
|
@@ -3487,7 +3481,7 @@ function entityContent(doc, key) {
|
|
|
3487
3481
|
}
|
|
3488
3482
|
function bases(map) {
|
|
3489
3483
|
const links = requireMap(map, "bases");
|
|
3490
|
-
return links.keys().sort((a, b) =>
|
|
3484
|
+
return links.keys().sort((a, b) => a < b ? -1 : a > b ? 1 : 0).map((key) => String(links.get(key)));
|
|
3491
3485
|
}
|
|
3492
3486
|
function owned(payload) {
|
|
3493
3487
|
const { baseEntityIds: _bases, ...fields } = payload;
|
|
@@ -3561,7 +3555,7 @@ function readEntityDocument(doc, allowSelectionConflicts = false) {
|
|
|
3561
3555
|
});
|
|
3562
3556
|
}
|
|
3563
3557
|
const project = {};
|
|
3564
|
-
for (const [key, value] of Object.entries(section(doc, "
|
|
3558
|
+
for (const [key, value] of Object.entries(section(doc, "attachments").toJSON())) {
|
|
3565
3559
|
if (typeof value !== "string") throw new Error(`Invalid project attachment ${key}`);
|
|
3566
3560
|
project[key] = currentId(doc, value, ids);
|
|
3567
3561
|
}
|
|
@@ -3608,6 +3602,7 @@ var LoroEntityDocument = class LoroEntityDocument {
|
|
|
3608
3602
|
"origins",
|
|
3609
3603
|
"relations",
|
|
3610
3604
|
"project",
|
|
3605
|
+
"attachments",
|
|
3611
3606
|
"ordering"
|
|
3612
3607
|
]) root(doc).ensureMergeableMap(name);
|
|
3613
3608
|
for (const row of rows.entities) apply(doc, {
|
|
@@ -3856,7 +3851,7 @@ function apply(doc, command) {
|
|
|
3856
3851
|
map.ensureMergeableMap("changes");
|
|
3857
3852
|
section(doc, "origins").set(row.entityId, row.entityId);
|
|
3858
3853
|
writeObject(map.ensureMergeableMap("content"), {}, owned(row.payload));
|
|
3859
|
-
writeBases(map, baseIds(row.payload));
|
|
3854
|
+
writeBases(doc, map, baseIds(row.payload));
|
|
3860
3855
|
break;
|
|
3861
3856
|
}
|
|
3862
3857
|
case "write": {
|
|
@@ -3867,7 +3862,7 @@ function apply(doc, command) {
|
|
|
3867
3862
|
writeObject(map.ensureMergeableMap("content"), before, after);
|
|
3868
3863
|
map.ensureMergeableMap("changes").set(command.token, true);
|
|
3869
3864
|
}
|
|
3870
|
-
writeBases(map, baseIds(command.payload));
|
|
3865
|
+
writeBases(doc, map, baseIds(command.payload));
|
|
3871
3866
|
break;
|
|
3872
3867
|
}
|
|
3873
3868
|
case "text": {
|
|
@@ -3916,16 +3911,19 @@ function apply(doc, command) {
|
|
|
3916
3911
|
break;
|
|
3917
3912
|
}
|
|
3918
3913
|
case "attach":
|
|
3919
|
-
section(doc, "
|
|
3914
|
+
section(doc, "attachments").set(command.slot, command.entityId);
|
|
3920
3915
|
break;
|
|
3921
3916
|
}
|
|
3922
3917
|
}
|
|
3923
|
-
function writeBases(map, ids) {
|
|
3918
|
+
function writeBases(doc, map, ids) {
|
|
3924
3919
|
const links = map.ensureMergeableMap("bases");
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
});
|
|
3920
|
+
const wanted = new Map(ids.map((id) => {
|
|
3921
|
+
const origin = section(doc, "origins").get(id);
|
|
3922
|
+
return [typeof origin === "string" ? origin : [...currentIds(doc)].find(([, current]) => current === id)?.[0] ?? id, id];
|
|
3923
|
+
}));
|
|
3924
|
+
if (wanted.size !== ids.length) throw new Error("Duplicate base entity family");
|
|
3925
|
+
for (const key of links.keys()) if (!wanted.has(key)) links.delete(key);
|
|
3926
|
+
for (const [key, id] of wanted) if (links.get(key) === void 0) links.set(key, id);
|
|
3929
3927
|
}
|
|
3930
3928
|
/** Numeric sub-spans must not silently quote different text after a collaborative edit. */
|
|
3931
3929
|
function selectionFingerprint(rows, id) {
|
|
@@ -3964,7 +3962,6 @@ function materialize(doc) {
|
|
|
3964
3962
|
const previous = byId.get(row.entityId);
|
|
3965
3963
|
if (isJsonObject(previous) && !equalJson(owned(previous), owned(next))) throw new Error("Immutable entity version collision");
|
|
3966
3964
|
if (!equalJson(previous, next)) byId.set(row.entityId, next);
|
|
3967
|
-
writeBases(workspace(doc, family(doc, row.entityId)), baseIds(row.payload));
|
|
3968
3965
|
}
|
|
3969
3966
|
const project = section(doc, "project");
|
|
3970
3967
|
for (const [slot, id] of Object.entries(state.project)) if (project.get(slot) !== id) project.set(slot, id);
|
package/dist/index.d.ts
CHANGED
|
@@ -454,6 +454,8 @@ interface PatchCaptionStyleInput {
|
|
|
454
454
|
}
|
|
455
455
|
interface InsertCaptionClipInput {
|
|
456
456
|
readonly timelineEntityId: string;
|
|
457
|
+
/** Existing generation identity for newly materialized Caption content, distinct from its Clip. */
|
|
458
|
+
readonly captionEntityId?: string;
|
|
457
459
|
/** Stable placed caption identity, distinct from the Caption content identity. */
|
|
458
460
|
readonly captionClipEntityId?: string;
|
|
459
461
|
/** Existing bases composed by this variant; includes an AudioScript text owner. */
|
|
@@ -592,7 +594,7 @@ interface EditorFoundation {
|
|
|
592
594
|
readonly rows: EntityRelationRows;
|
|
593
595
|
readonly timelineEntityId: string;
|
|
594
596
|
readonly trackEntityIds: Readonly<Record<EditorTrackRole, string>>;
|
|
595
|
-
/**
|
|
597
|
+
/** Initial or current AudioScript content ID selected by the foundation. */
|
|
596
598
|
readonly audioScriptEntityId: string;
|
|
597
599
|
}
|
|
598
600
|
/**
|
|
@@ -602,7 +604,7 @@ interface EditorFoundation {
|
|
|
602
604
|
* Image/Video/Audio/Voice Entity must carry its own external locator, every
|
|
603
605
|
* external asset id has exactly one claimant, and no media variant may be
|
|
604
606
|
* bound through a legacy `physical-asset` Relation. Dual-entity media graphs
|
|
605
|
-
* are rejected, not migrated. Caption composes AudioScript text and
|
|
607
|
+
* are rejected, not migrated. Caption composes AudioScript text and may associate with a physical text Asset.
|
|
606
608
|
*/
|
|
607
609
|
declare function assertCanonicalEditorResources(rows: EntityRelationRows): void;
|
|
608
610
|
/**
|
|
@@ -613,7 +615,7 @@ declare function assertCanonicalEditorResources(rows: EntityRelationRows): void;
|
|
|
613
615
|
*
|
|
614
616
|
* 1. every Image/Video/Audio/Voice Entity carries its own Asset `external`
|
|
615
617
|
* identity;
|
|
616
|
-
* 2. no `physical-asset` Relation may bind a media variant
|
|
618
|
+
* 2. no `physical-asset` Relation may bind a media variant;
|
|
617
619
|
* 3. a self-carried media identity is immutable — it cannot be rewritten to
|
|
618
620
|
* another asset id.
|
|
619
621
|
*
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as reassignSpeechesToVideoClipsByTime, A as isJsonObject, B as VideoDocumentValidationError, C as assembleEntityContent, D as selectAudioScriptSegments, E as findComposedAudioScript, F as buildInitialVideoDocument, G as LANE_KINDS_IN_STACK_ORDER, H as validateVideoDocument, I as buildSpeechHostMap, J as laneTrackId, K as ensureLaneTrack, L as derivePositionFromAbs, M as createRelationId, N as hasSequence, O as updateEntityFields, P as isMediaAssetVariantKind, Q as fillMainTrackTimeGaps, R as fromVideoDocument, S as assembleCaptionContent, T as assembleScriptText, U as partUnionSchema, V as assertValidVideoDocument, W as videoDocumentSchema, X as cascadeAfterVideoClipChanges, Y as solveVideoDocument, Z as arrangeMainTrackSeamlessly, _ as EntityProjectionGraph, _t as bytesToBase64, a as applyEntityTimelineProjection, at as isEmptyVideoClip, b as decodeEntityRelationRows, c as writeVideoDocumentToDraft, ct as DEFAULT_UNIT_TIME_MS, d as LoroEntityDocument, dt as effectiveVideoClipDurationMs, et as recalculateTimelineDuration, f as LoroEntityDraft, ft as speedOf, g as projectEntityTimeline, gt as base64ToBytes, h as equalJson, ht as videoDocumentMirrorSchema, i as MirrorVideoDocumentAdapter, it as TIMELINE_SKELETON_DURATION_MS, j as createEntityId, k as variantBaseEntityIds, l as readVideoDocumentFromDraft, lt as ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, m as entityOrderGroups, mt as recordEntries, n as createPlainMemoryAdapter, nt as resolveSpeechOverlapByShiftingVideos, o as createMirrorVideoDocument, ot as partDurationMs, p as readEntityDocument, pt as partUnionToDraft, q as findLaneTrack, r as generatePartId, rt as syncAggregatedClipsTimePosition, s as createMirrorVideoDocumentAdapter, st as safeDurationMs, t as PlainMemoryAdapter, tt as resolveAllSpeechOverlaps, u as LORO_ENTITY_SCHEMA, ut as VIDEO_DOCUMENT_SCHEMA_VERSION, v as resolveEntityTimelineLayout, w as assemblePhoneticScriptContent, x as ScriptCompositionError, y as EntityTimelineProjectionError, z as toVideoDocument } from "./document-
|
|
1
|
+
import { $ as reassignSpeechesToVideoClipsByTime, A as isJsonObject, B as VideoDocumentValidationError, C as assembleEntityContent, D as selectAudioScriptSegments, E as findComposedAudioScript, F as buildInitialVideoDocument, G as LANE_KINDS_IN_STACK_ORDER, H as validateVideoDocument, I as buildSpeechHostMap, J as laneTrackId, K as ensureLaneTrack, L as derivePositionFromAbs, M as createRelationId, N as hasSequence, O as updateEntityFields, P as isMediaAssetVariantKind, Q as fillMainTrackTimeGaps, R as fromVideoDocument, S as assembleCaptionContent, T as assembleScriptText, U as partUnionSchema, V as assertValidVideoDocument, W as videoDocumentSchema, X as cascadeAfterVideoClipChanges, Y as solveVideoDocument, Z as arrangeMainTrackSeamlessly, _ as EntityProjectionGraph, _t as bytesToBase64, a as applyEntityTimelineProjection, at as isEmptyVideoClip, b as decodeEntityRelationRows, c as writeVideoDocumentToDraft, ct as DEFAULT_UNIT_TIME_MS, d as LoroEntityDocument, dt as effectiveVideoClipDurationMs, et as recalculateTimelineDuration, f as LoroEntityDraft, ft as speedOf, g as projectEntityTimeline, gt as base64ToBytes, h as equalJson, ht as videoDocumentMirrorSchema, i as MirrorVideoDocumentAdapter, it as TIMELINE_SKELETON_DURATION_MS, j as createEntityId, k as variantBaseEntityIds, l as readVideoDocumentFromDraft, lt as ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, m as entityOrderGroups, mt as recordEntries, n as createPlainMemoryAdapter, nt as resolveSpeechOverlapByShiftingVideos, o as createMirrorVideoDocument, ot as partDurationMs, p as readEntityDocument, pt as partUnionToDraft, q as findLaneTrack, r as generatePartId, rt as syncAggregatedClipsTimePosition, s as createMirrorVideoDocumentAdapter, st as safeDurationMs, t as PlainMemoryAdapter, tt as resolveAllSpeechOverlaps, u as LORO_ENTITY_SCHEMA, ut as VIDEO_DOCUMENT_SCHEMA_VERSION, v as resolveEntityTimelineLayout, w as assemblePhoneticScriptContent, x as ScriptCompositionError, y as EntityTimelineProjectionError, z as toVideoDocument } from "./document-CF-q_mRy.js";
|
|
2
2
|
import { addSpeechesInputSchema, addVideoClipsInputSchema, adjustBgmVolumeInputSchema, adjustSpeechVolumeInputSchema, adjustVideoClipDurationInputSchema, adjustVideoClipVolumeInputSchema, changeSpeechScriptInputSchema, changeSpeechVoiceInputSchema, deleteBgmInputSchema, deleteSpeechesInputSchema, deleteVideoClipsInputSchema, moveSpeechesInputSchema, moveVideoClipsByAnchorInputSchema, moveVideoClipsInputSchema, replaceVideoClipContentInputSchema, replaceVideoClipSequenceInputSchema, setBgmInputSchema, setCaptionStyleInputSchema, setCaptionVisibilityInputSchema, setVideoClipSpeedShiftInputSchema, t as schemas_exports } from "./schemas.js";
|
|
3
3
|
import { LoroDoc, VersionVector } from "loro-crdt";
|
|
4
4
|
import { ClientServerSynchronizer, DocManager } from "@mengine/sync";
|
|
@@ -292,7 +292,7 @@ const roleOrder$1 = {
|
|
|
292
292
|
* Image/Video/Audio/Voice Entity must carry its own external locator, every
|
|
293
293
|
* external asset id has exactly one claimant, and no media variant may be
|
|
294
294
|
* bound through a legacy `physical-asset` Relation. Dual-entity media graphs
|
|
295
|
-
* are rejected, not migrated. Caption composes AudioScript text and
|
|
295
|
+
* are rejected, not migrated. Caption composes AudioScript text and may associate with a physical text Asset.
|
|
296
296
|
*/
|
|
297
297
|
function assertCanonicalEditorResources(rows) {
|
|
298
298
|
if (rows.entities.filter((row) => row.entityKind === "timeline").length > 1) throw new EntityTimelineProjectionError("Editor requires exactly one Timeline");
|
|
@@ -323,7 +323,7 @@ function assertCanonicalEditorResources(rows) {
|
|
|
323
323
|
*
|
|
324
324
|
* 1. every Image/Video/Audio/Voice Entity carries its own Asset `external`
|
|
325
325
|
* identity;
|
|
326
|
-
* 2. no `physical-asset` Relation may bind a media variant
|
|
326
|
+
* 2. no `physical-asset` Relation may bind a media variant;
|
|
327
327
|
* 3. a self-carried media identity is immutable — it cannot be rewritten to
|
|
328
328
|
* another asset id.
|
|
329
329
|
*
|
|
@@ -358,10 +358,9 @@ function memotaLocator(value) {
|
|
|
358
358
|
};
|
|
359
359
|
}
|
|
360
360
|
/**
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
* path, so both produce the same canonical structure.
|
|
361
|
+
* Bootstrap an empty script when the foundation has no candidate. Without an
|
|
362
|
+
* explicit project attachment, multiple candidates are ambiguous. Existing
|
|
363
|
+
* content IDs are reused here; Loro editing advances their immutable versions.
|
|
365
364
|
*/
|
|
366
365
|
function ensureDocumentAudioScript(entities, idFactory) {
|
|
367
366
|
const scripts = entities.filter((row) => row.entityKind === "audio-script");
|
|
@@ -1377,7 +1376,7 @@ var EntityTimelineEditor = class {
|
|
|
1377
1376
|
const selections = captionSelections(input.selections);
|
|
1378
1377
|
const track = this.ensureRoleTrack(draft, input.timelineEntityId, "caption");
|
|
1379
1378
|
const content = {
|
|
1380
|
-
entityId: this.mintEntityId(draft),
|
|
1379
|
+
entityId: input.captionEntityId === void 0 ? this.mintEntityId(draft) : requireAvailableEntityId(draft, input.captionEntityId),
|
|
1381
1380
|
entityKind: "caption",
|
|
1382
1381
|
payload: {
|
|
1383
1382
|
extent: {
|
package/dist/testing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _t as bytesToBase64, gt as base64ToBytes, s as createMirrorVideoDocumentAdapter, ut as VIDEO_DOCUMENT_SCHEMA_VERSION } from "./document-
|
|
1
|
+
import { _t as bytesToBase64, gt as base64ToBytes, s as createMirrorVideoDocumentAdapter, ut as VIDEO_DOCUMENT_SCHEMA_VERSION } from "./document-CF-q_mRy.js";
|
|
2
2
|
import { t as classifyUpdate } from "./loro-relay-doc-ssdYpuef.js";
|
|
3
3
|
import { LoroDoc, VersionVector, encodeFrontiers } from "loro-crdt";
|
|
4
4
|
//#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": "1.3.1-alpha.
|
|
3
|
+
"version": "1.3.1-alpha.12",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"immer": "^10.2.0",
|
|
29
29
|
"loro-mirror": "^2.2.0",
|
|
30
30
|
"zod": "^4.4.3",
|
|
31
|
-
"@mengine/storage": "1.3.1-alpha.
|
|
32
|
-
"@mengine/sync": "1.3.1-alpha.
|
|
33
|
-
"@mengine/utils": "1.3.1-alpha.
|
|
31
|
+
"@mengine/storage": "1.3.1-alpha.12",
|
|
32
|
+
"@mengine/sync": "1.3.1-alpha.12",
|
|
33
|
+
"@mengine/utils": "1.3.1-alpha.12"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^25.9.1",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"typescript": "^6.0.3",
|
|
41
41
|
"vite-plugin-wasm": "^3.6.0",
|
|
42
42
|
"vite-plus": "^0.1.23",
|
|
43
|
-
"@mengine/
|
|
44
|
-
"@mengine/
|
|
43
|
+
"@mengine/medeo-dsl": "0.0.0",
|
|
44
|
+
"@mengine/idl-codegen": "0.0.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"loro-crdt": "^1.13.6"
|