@mengine/medeo-client 1.4.1-alpha.2 → 1.4.1-alpha.4
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.
|
@@ -130,6 +130,7 @@ const captionStyle$1 = schema.LoroMap({
|
|
|
130
130
|
position_y: schema.Number({ required: false })
|
|
131
131
|
}, { required: false });
|
|
132
132
|
const captionPart = schema.LoroMap({
|
|
133
|
+
display_cues: schema.String({ required: false }).transform(jsonTransform()),
|
|
133
134
|
id: schema.String(),
|
|
134
135
|
initial_duration_ms: schema.Number(),
|
|
135
136
|
speech_part_id: schema.String({ required: false }),
|
|
@@ -3159,7 +3160,9 @@ function projectEntityTimeline(rows, meta) {
|
|
|
3159
3160
|
caption_ids: captionIds
|
|
3160
3161
|
} };
|
|
3161
3162
|
} else if (track.role === "caption") {
|
|
3162
|
-
const
|
|
3163
|
+
const assembled = assembleCaptionContent(rows, content.entityId);
|
|
3164
|
+
const text = assembled.text;
|
|
3165
|
+
const cues = captionDisplayCues(assembled, marker, placement.duration);
|
|
3163
3166
|
if (marker.payload.timeRemapping !== void 0) fail("Caption timeRemapping is not supported by this reader");
|
|
3164
3167
|
const style = captionStyle(content.payload.style);
|
|
3165
3168
|
const anchor = placement.anchorClipEntityId === void 0 ? void 0 : layout.clips.get(placement.anchorClipEntityId);
|
|
@@ -3168,6 +3171,7 @@ function projectEntityTimeline(rows, meta) {
|
|
|
3168
3171
|
id: clip.entityId,
|
|
3169
3172
|
kind: "caption",
|
|
3170
3173
|
text,
|
|
3174
|
+
...cues === void 0 ? {} : { display_cues: cues },
|
|
3171
3175
|
speech_part_id: anchoredToSpeech ? placement.anchorClipEntityId : void 0,
|
|
3172
3176
|
start_ms: anchoredToSpeech ? placement.anchorOffset : 0,
|
|
3173
3177
|
initial_duration_ms: placement.duration,
|
|
@@ -3304,8 +3308,34 @@ function videoSpeed(content, marker, placement) {
|
|
|
3304
3308
|
config: { linear: { speed: rate } }
|
|
3305
3309
|
};
|
|
3306
3310
|
}
|
|
3311
|
+
/** Preserve selected text intervals without minting synthetic editable Clip identities. */
|
|
3312
|
+
function captionDisplayCues(assembled, marker, duration) {
|
|
3313
|
+
const ranges = assembled.caption.payload.segmentRanges;
|
|
3314
|
+
if (!Array.isArray(ranges)) return void 0;
|
|
3315
|
+
const source = range(marker.payload.sourceRange, "Caption sourceRange");
|
|
3316
|
+
const scale = duration / (source.end - source.start);
|
|
3317
|
+
return assembled.segments.flatMap((segment) => {
|
|
3318
|
+
const timing = ranges.find((entry) => object(entry) && entry.segmentId === segment.segmentId);
|
|
3319
|
+
if (!object(timing)) fail(`Caption timing is missing for selected segment ${segment.segmentId}`);
|
|
3320
|
+
const intrinsic = range({
|
|
3321
|
+
start: timing.startMs,
|
|
3322
|
+
end: timing.endMs
|
|
3323
|
+
}, "Caption segmentRange");
|
|
3324
|
+
const start = Math.max(source.start, intrinsic.start);
|
|
3325
|
+
const end = Math.min(source.end, intrinsic.end);
|
|
3326
|
+
if (end <= start) return [];
|
|
3327
|
+
const startMs = Math.round((start - source.start) * scale);
|
|
3328
|
+
const endMs = Math.round((end - source.start) * scale);
|
|
3329
|
+
return endMs > startMs ? [{
|
|
3330
|
+
segmentId: segment.segmentId,
|
|
3331
|
+
text: segment.text,
|
|
3332
|
+
startMs,
|
|
3333
|
+
durationMs: endMs - startMs
|
|
3334
|
+
}] : [];
|
|
3335
|
+
});
|
|
3336
|
+
}
|
|
3307
3337
|
//#endregion
|
|
3308
|
-
//#region src/entity-crdt/
|
|
3338
|
+
//#region src/entity-crdt/field-changes.ts
|
|
3309
3339
|
const atomicFields = new Set([
|
|
3310
3340
|
"sequence",
|
|
3311
3341
|
"sourceRange",
|
|
@@ -3314,14 +3344,131 @@ const atomicFields = new Set([
|
|
|
3314
3344
|
"extent",
|
|
3315
3345
|
"timeRemapping",
|
|
3316
3346
|
"textRange",
|
|
3317
|
-
"external"
|
|
3347
|
+
"external",
|
|
3348
|
+
"coordinateSpace"
|
|
3318
3349
|
]);
|
|
3319
3350
|
const textFields = new Set(["text", "phonemeScript"]);
|
|
3320
3351
|
const orderedFields = new Set([
|
|
3321
3352
|
"segments",
|
|
3322
3353
|
"selections",
|
|
3354
|
+
"segmentRanges",
|
|
3323
3355
|
"baseEntityIds"
|
|
3324
3356
|
]);
|
|
3357
|
+
const unsafeKeys = new Set([
|
|
3358
|
+
"__proto__",
|
|
3359
|
+
"prototype",
|
|
3360
|
+
"constructor"
|
|
3361
|
+
]);
|
|
3362
|
+
function listElementId(value) {
|
|
3363
|
+
const id = typeof value === "string" ? value : isJsonObject(value) ? value.segmentId : void 0;
|
|
3364
|
+
if (typeof id !== "string" || !id.trim()) throw new Error("List elements require a nonempty segmentId or string identity");
|
|
3365
|
+
return id;
|
|
3366
|
+
}
|
|
3367
|
+
function assertFieldChanges(changes) {
|
|
3368
|
+
if (!Array.isArray(changes) || changes.length === 0) throw new Error("changes must be a nonempty array");
|
|
3369
|
+
for (const change of changes) {
|
|
3370
|
+
if (!isJsonObject(change) || ![
|
|
3371
|
+
"set",
|
|
3372
|
+
"unset",
|
|
3373
|
+
"text.splice",
|
|
3374
|
+
"list.insert",
|
|
3375
|
+
"list.move",
|
|
3376
|
+
"list.remove"
|
|
3377
|
+
].includes(change.op)) throw new Error("Unknown field operation");
|
|
3378
|
+
if (!Array.isArray(change.path) || !change.path.length || typeof change.path[0] !== "string") throw new Error("Field paths must start with a field name");
|
|
3379
|
+
for (const part of change.path) if (typeof part === "string") {
|
|
3380
|
+
if (!part || unsafeKeys.has(part)) throw new Error("Invalid field name");
|
|
3381
|
+
} else if (!isJsonObject(part) || Object.keys(part).length !== 1 || typeof part.elementId !== "string" || !part.elementId.trim()) throw new Error("List paths require { elementId }; numeric indices are not supported");
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
/** Resolve against the sequential causal view; the numeric path never crosses the API boundary. */
|
|
3385
|
+
function resolveFieldPath(payload, path) {
|
|
3386
|
+
let value = payload;
|
|
3387
|
+
const resolved = [];
|
|
3388
|
+
for (const [index, part] of path.entries()) if (typeof part === "string") {
|
|
3389
|
+
if (!isJsonObject(value)) throw new Error(`Field path does not reach a map: ${part}`);
|
|
3390
|
+
if (index < path.length - 1 && atomicFields.has(part)) throw new Error(`Atomic field ${part} must be changed as one value`);
|
|
3391
|
+
resolved.push(part);
|
|
3392
|
+
value = value[part];
|
|
3393
|
+
} else {
|
|
3394
|
+
if (!Array.isArray(value)) throw new Error("Element selector requires a list");
|
|
3395
|
+
const matches = value.flatMap((item, i) => listElementId(item) === part.elementId ? [i] : []);
|
|
3396
|
+
if (matches.length !== 1) throw new Error(`Missing or ambiguous list element ${part.elementId}`);
|
|
3397
|
+
resolved.push(matches[0]);
|
|
3398
|
+
value = value[matches[0]];
|
|
3399
|
+
}
|
|
3400
|
+
return resolved;
|
|
3401
|
+
}
|
|
3402
|
+
/** Detached plan evaluation. Native compilation replays the original operations, not this snapshot. */
|
|
3403
|
+
function applyFieldChanges(payload, changes) {
|
|
3404
|
+
assertFieldChanges(changes);
|
|
3405
|
+
const result = structuredClone(payload);
|
|
3406
|
+
for (const change of changes) {
|
|
3407
|
+
const path = resolveFieldPath(result, change.path);
|
|
3408
|
+
const key = path.at(-1);
|
|
3409
|
+
if (typeof key !== "string") throw new Error("Change fields inside a list element or use list operations");
|
|
3410
|
+
let parent = result;
|
|
3411
|
+
for (const part of path.slice(0, -1)) parent = parent[part];
|
|
3412
|
+
if (!isJsonObject(parent)) throw new Error("Field parent is not a map");
|
|
3413
|
+
const mutable = parent;
|
|
3414
|
+
const value = mutable[key];
|
|
3415
|
+
if ([
|
|
3416
|
+
"entityId",
|
|
3417
|
+
"entityKind",
|
|
3418
|
+
"entity_id",
|
|
3419
|
+
"entity_kind",
|
|
3420
|
+
"segmentId"
|
|
3421
|
+
].includes(key)) throw new Error(`Identity field ${key} cannot be edited`);
|
|
3422
|
+
switch (change.op) {
|
|
3423
|
+
case "set":
|
|
3424
|
+
if (textFields.has(key) || orderedFields.has(key) || !atomicFields.has(key) && (isJsonObject(value) || isJsonObject(change.value) || Array.isArray(value) || Array.isArray(change.value))) throw new Error(`Field ${key} requires a text, list, or leaf operation; snapshot replacement is not allowed`);
|
|
3425
|
+
if (change.value === void 0 || !isJsonObject({ value: change.value })) throw new Error("set requires a JSON value");
|
|
3426
|
+
if (value !== void 0 && value !== null && change.value !== null && typeof value !== typeof change.value) throw new Error(`Field ${key} cannot change type`);
|
|
3427
|
+
mutable[key] = structuredClone(change.value);
|
|
3428
|
+
break;
|
|
3429
|
+
case "unset":
|
|
3430
|
+
if (!Object.hasOwn(parent, key)) throw new Error(`Field ${key} is absent`);
|
|
3431
|
+
delete mutable[key];
|
|
3432
|
+
break;
|
|
3433
|
+
case "text.splice": {
|
|
3434
|
+
if (!textFields.has(key) || typeof value !== "string") throw new Error(`Field ${key} is not collaborative text`);
|
|
3435
|
+
const chars = Array.from(value);
|
|
3436
|
+
if (!Number.isSafeInteger(change.index) || !Number.isSafeInteger(change.deleteCount) || change.index < 0 || change.deleteCount < 0 || change.index + change.deleteCount > chars.length || typeof change.text !== "string") throw new Error("Invalid text splice range");
|
|
3437
|
+
chars.splice(change.index, change.deleteCount, ...Array.from(change.text));
|
|
3438
|
+
mutable[key] = chars.join("");
|
|
3439
|
+
break;
|
|
3440
|
+
}
|
|
3441
|
+
default: {
|
|
3442
|
+
if (!orderedFields.has(key) || !Array.isArray(value)) throw new Error(`Field ${key} is not a collaborative list`);
|
|
3443
|
+
const ids = value.map(listElementId);
|
|
3444
|
+
if (new Set(ids).size !== ids.length) throw new Error("Duplicate collaborative list identity");
|
|
3445
|
+
const requireIndex = (id) => {
|
|
3446
|
+
const index = ids.indexOf(id);
|
|
3447
|
+
if (index < 0) throw new Error(`Unknown list element ${id}`);
|
|
3448
|
+
return index;
|
|
3449
|
+
};
|
|
3450
|
+
if (change.op === "list.remove") value.splice(requireIndex(change.elementId), 1);
|
|
3451
|
+
else {
|
|
3452
|
+
if (change.beforeElementId !== null && typeof change.beforeElementId !== "string") throw new Error("beforeElementId must be an identity or null");
|
|
3453
|
+
const before = change.beforeElementId === null ? value.length : requireIndex(change.beforeElementId);
|
|
3454
|
+
if (change.op === "list.insert") {
|
|
3455
|
+
const id = listElementId(change.value);
|
|
3456
|
+
if (ids.includes(id)) throw new Error(`Duplicate list element ${id}`);
|
|
3457
|
+
value.splice(before, 0, structuredClone(change.value));
|
|
3458
|
+
} else {
|
|
3459
|
+
if (change.elementId === change.beforeElementId) throw new Error("Cannot move a list element before itself");
|
|
3460
|
+
const from = requireIndex(change.elementId);
|
|
3461
|
+
const [item] = value.splice(from, 1);
|
|
3462
|
+
value.splice(before > from ? before - 1 : before, 0, item);
|
|
3463
|
+
}
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
return result;
|
|
3469
|
+
}
|
|
3470
|
+
//#endregion
|
|
3471
|
+
//#region src/entity-crdt/json-containers.ts
|
|
3325
3472
|
function equalJson(a, b) {
|
|
3326
3473
|
return canonicalJson(a) === canonicalJson(b);
|
|
3327
3474
|
}
|
|
@@ -3342,24 +3489,19 @@ function writeObject(map, before, after) {
|
|
|
3342
3489
|
else map.set(key, value);
|
|
3343
3490
|
}
|
|
3344
3491
|
}
|
|
3345
|
-
function itemKey(value) {
|
|
3346
|
-
if (typeof value === "string") return value;
|
|
3347
|
-
if (isJsonObject(value) && typeof value.segmentId === "string") return value.segmentId;
|
|
3348
|
-
throw new Error("Collaborative lists require stable segmentId or unique string identities");
|
|
3349
|
-
}
|
|
3350
3492
|
function readItem(list, index) {
|
|
3351
3493
|
const value = list.get(index);
|
|
3352
3494
|
return value instanceof LoroMap ? value.toJSON() : value;
|
|
3353
3495
|
}
|
|
3354
3496
|
function writeList(list, values) {
|
|
3355
|
-
const wanted = values.map(
|
|
3497
|
+
const wanted = values.map(listElementId);
|
|
3356
3498
|
if (new Set(wanted).size !== wanted.length) throw new Error("Duplicate collaborative list identity");
|
|
3357
|
-
for (let index = list.length - 1; index >= 0; index--) if (!wanted.includes(
|
|
3499
|
+
for (let index = list.length - 1; index >= 0; index--) if (!wanted.includes(listElementId(readItem(list, index)))) list.delete(index, 1);
|
|
3358
3500
|
for (let index = 0; index < values.length; index++) {
|
|
3359
3501
|
const value = values[index];
|
|
3360
3502
|
const key = wanted[index];
|
|
3361
3503
|
let found = -1;
|
|
3362
|
-
for (let cursor = index; cursor < list.length; cursor++) if (
|
|
3504
|
+
for (let cursor = index; cursor < list.length; cursor++) if (listElementId(readItem(list, cursor)) === key) {
|
|
3363
3505
|
found = cursor;
|
|
3364
3506
|
break;
|
|
3365
3507
|
}
|
|
@@ -3383,6 +3525,53 @@ function requireText(map, path) {
|
|
|
3383
3525
|
if (!(value instanceof LoroText)) throw new Error("Field is not collaborative text");
|
|
3384
3526
|
return value;
|
|
3385
3527
|
}
|
|
3528
|
+
/** Apply the authored operation directly, preserving text positions and moved item identity. */
|
|
3529
|
+
function applyNativeFieldChange(map, path, change) {
|
|
3530
|
+
let parent = map;
|
|
3531
|
+
for (const part of path.slice(0, -1)) if (parent instanceof LoroMap && typeof part === "string") parent = parent.get(part);
|
|
3532
|
+
else if (parent instanceof LoroMovableList && typeof part === "number") parent = parent.get(part);
|
|
3533
|
+
else throw new Error("Invalid native field path");
|
|
3534
|
+
const key = path.at(-1);
|
|
3535
|
+
if (!(parent instanceof LoroMap) || typeof key !== "string") throw new Error("Invalid native field parent");
|
|
3536
|
+
if (change.op === "set") {
|
|
3537
|
+
parent.set(key, change.value);
|
|
3538
|
+
return;
|
|
3539
|
+
}
|
|
3540
|
+
if (change.op === "unset") {
|
|
3541
|
+
parent.delete(key);
|
|
3542
|
+
return;
|
|
3543
|
+
}
|
|
3544
|
+
const value = parent.get(key);
|
|
3545
|
+
if (change.op === "text.splice") {
|
|
3546
|
+
if (!(value instanceof LoroText)) throw new Error("Field is not collaborative text");
|
|
3547
|
+
const start = value.convertPos(change.index, "unicode", "utf16");
|
|
3548
|
+
const end = value.convertPos(change.index + change.deleteCount, "unicode", "utf16");
|
|
3549
|
+
value.splice(start, end - start, change.text);
|
|
3550
|
+
return;
|
|
3551
|
+
}
|
|
3552
|
+
if (!(value instanceof LoroMovableList)) throw new Error("Field is not a collaborative list");
|
|
3553
|
+
applyNativeListChange(value, change);
|
|
3554
|
+
}
|
|
3555
|
+
function applyNativeListChange(list, change) {
|
|
3556
|
+
const ids = Array.from({ length: list.length }, (_, i) => listElementId(readItem(list, i)));
|
|
3557
|
+
const index = (id) => {
|
|
3558
|
+
const found = ids.indexOf(id);
|
|
3559
|
+
if (found < 0) throw new Error(`Unknown list element ${id}`);
|
|
3560
|
+
return found;
|
|
3561
|
+
};
|
|
3562
|
+
if (change.op === "list.remove") {
|
|
3563
|
+
list.delete(index(change.elementId), 1);
|
|
3564
|
+
return;
|
|
3565
|
+
}
|
|
3566
|
+
const before = change.beforeElementId === null ? list.length : index(change.beforeElementId);
|
|
3567
|
+
if (change.op === "list.insert") if (isJsonObject(change.value)) writeObject(list.insertContainer(before, new LoroMap()), {}, change.value);
|
|
3568
|
+
else list.insert(before, change.value);
|
|
3569
|
+
else {
|
|
3570
|
+
const from = index(change.elementId);
|
|
3571
|
+
const to = before > from ? before - 1 : before;
|
|
3572
|
+
if (from !== to) list.move(from, to);
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3386
3575
|
//#endregion
|
|
3387
3576
|
//#region src/entity-crdt/ordering.ts
|
|
3388
3577
|
/** Domain order is scoped by membership; relation storage has no global order. */
|
|
@@ -3709,8 +3898,10 @@ var LoroEntityDraft = class {
|
|
|
3709
3898
|
doc;
|
|
3710
3899
|
commands = [];
|
|
3711
3900
|
selectedRoots = /* @__PURE__ */ new Set();
|
|
3901
|
+
relationAliases = /* @__PURE__ */ new Map();
|
|
3712
3902
|
constructor(doc) {
|
|
3713
3903
|
this.doc = doc;
|
|
3904
|
+
for (const row of this.snapshot().rows.relations) this.relationAliases.set(row.relationId, this.relationRoot(row.relationId));
|
|
3714
3905
|
}
|
|
3715
3906
|
snapshot() {
|
|
3716
3907
|
return readEntityDocument(this.doc, true);
|
|
@@ -3723,6 +3914,15 @@ var LoroEntityDraft = class {
|
|
|
3723
3914
|
token: globalThis.crypto.randomUUID()
|
|
3724
3915
|
});
|
|
3725
3916
|
}
|
|
3917
|
+
/** Project the final scalar placement intents onto the existing native ordering containers. */
|
|
3918
|
+
reconcileOrder(rows) {
|
|
3919
|
+
const before = new Map([...entityOrderGroups(this.snapshot().rows)].map(([id, ids]) => [family(this.doc, id), ids.map((id) => family(this.doc, id))]));
|
|
3920
|
+
const after = new Map([...entityOrderGroups(rows)].map(([id, ids]) => [family(this.doc, id), ids.map((id) => family(this.doc, id))]));
|
|
3921
|
+
for (const group of new Set([...before.keys(), ...after.keys()])) {
|
|
3922
|
+
const next = after.get(group) ?? [];
|
|
3923
|
+
if (!equalJson(before.get(group) ?? [], next)) this.order(group, next);
|
|
3924
|
+
}
|
|
3925
|
+
}
|
|
3726
3926
|
create(row) {
|
|
3727
3927
|
this.record({
|
|
3728
3928
|
type: "create",
|
|
@@ -3763,6 +3963,8 @@ var LoroEntityDraft = class {
|
|
|
3763
3963
|
});
|
|
3764
3964
|
}
|
|
3765
3965
|
relationRoot(relationId) {
|
|
3966
|
+
const alias = this.relationAliases.get(relationId);
|
|
3967
|
+
if (alias !== void 0) return alias;
|
|
3766
3968
|
const ids = currentIds(this.doc);
|
|
3767
3969
|
for (const key of section(this.doc, "relations").keys()) {
|
|
3768
3970
|
const map = section(this.doc, "relations").get(key);
|
|
@@ -3770,7 +3972,7 @@ var LoroEntityDraft = class {
|
|
|
3770
3972
|
const identity = map.get("identity");
|
|
3771
3973
|
if (identity.endpoints.some((id) => !ids.has(family(this.doc, id)))) continue;
|
|
3772
3974
|
const endpoints = identity.endpoints.map((id) => currentId(this.doc, id, ids));
|
|
3773
|
-
if ((equalJson(endpoints, identity.endpoints) ? key : `relation_${hash([key, endpoints])}`) === relationId) return key;
|
|
3975
|
+
if ((equalJson(endpoints, identity.endpoints) ? key : `relation_${hash([key, endpoints])}`) === relationId || key === relationId) return key;
|
|
3774
3976
|
}
|
|
3775
3977
|
throw new Error(`Unknown relation ${relationId}`);
|
|
3776
3978
|
}
|
|
@@ -3817,6 +4019,50 @@ var LoroEntityDraft = class {
|
|
|
3817
4019
|
token: globalThis.crypto.randomUUID()
|
|
3818
4020
|
});
|
|
3819
4021
|
}
|
|
4022
|
+
/** Generic assembled-field edit compiled at the author's causal position. */
|
|
4023
|
+
change(entityId, changes) {
|
|
4024
|
+
assertFieldChanges(changes);
|
|
4025
|
+
for (const raw of changes) {
|
|
4026
|
+
const change = clone(raw);
|
|
4027
|
+
if (change.path[0] === "baseEntityIds") {
|
|
4028
|
+
if (change.op === "list.insert" && typeof change.value === "string") change.value = currentId(this.doc, change.value);
|
|
4029
|
+
if (change.op === "list.remove" || change.op === "list.move") change.elementId = currentId(this.doc, change.elementId);
|
|
4030
|
+
if ((change.op === "list.insert" || change.op === "list.move") && change.beforeElementId !== null) change.beforeElementId = currentId(this.doc, change.beforeElementId);
|
|
4031
|
+
}
|
|
4032
|
+
const state = this.snapshot();
|
|
4033
|
+
const id = createEntityId(currentId(this.doc, entityId));
|
|
4034
|
+
const owner = resolveEntityFieldOwner(state.rows, id, change.path[0]);
|
|
4035
|
+
const row = state.rows.entities.find((row) => row.entityId === owner);
|
|
4036
|
+
if (equalJson(row.payload, applyFieldChanges(row.payload, [change]))) continue;
|
|
4037
|
+
this.record({
|
|
4038
|
+
type: "field",
|
|
4039
|
+
root: family(this.doc, owner),
|
|
4040
|
+
path: resolveFieldPath(row.payload, change.path),
|
|
4041
|
+
change: clone(change),
|
|
4042
|
+
token: globalThis.crypto.randomUUID()
|
|
4043
|
+
});
|
|
4044
|
+
}
|
|
4045
|
+
}
|
|
4046
|
+
changeRelation(relationId, changes) {
|
|
4047
|
+
assertFieldChanges(changes);
|
|
4048
|
+
const key = this.relationRoot(relationId);
|
|
4049
|
+
const map = section(this.doc, "relations").get(key);
|
|
4050
|
+
if (!(map instanceof LoroMap) || map.get("deleted") === true) throw new Error("Unknown relation");
|
|
4051
|
+
for (const change of changes) {
|
|
4052
|
+
if (!["metadata", "trace"].includes(change.path[0]) || change.path.length < 2) throw new Error("Relation changes may only edit metadata or trace fields");
|
|
4053
|
+
const payload = {
|
|
4054
|
+
metadata: requireMap(map, "metadata").toJSON(),
|
|
4055
|
+
trace: requireMap(map, "trace").toJSON()
|
|
4056
|
+
};
|
|
4057
|
+
applyFieldChanges(payload, [change]);
|
|
4058
|
+
this.record({
|
|
4059
|
+
type: "relation-field",
|
|
4060
|
+
root: key,
|
|
4061
|
+
path: resolveFieldPath(payload, change.path),
|
|
4062
|
+
change: clone(change)
|
|
4063
|
+
});
|
|
4064
|
+
}
|
|
4065
|
+
}
|
|
3820
4066
|
captureSelectionBaselines() {
|
|
3821
4067
|
const state = this.snapshot();
|
|
3822
4068
|
for (const key of this.selectedRoots) {
|
|
@@ -3833,6 +4079,7 @@ var LoroEntityDraft = class {
|
|
|
3833
4079
|
record(command) {
|
|
3834
4080
|
if (command.type === "create") this.selectedRoots.add(command.row.entityId);
|
|
3835
4081
|
if (command.type === "write" && !equalJson(content(workspace(this.doc, command.root)).selections, command.payload.selections)) this.selectedRoots.add(command.root);
|
|
4082
|
+
if (command.type === "field" && command.path[0] === "selections") this.selectedRoots.add(command.root);
|
|
3836
4083
|
apply(this.doc, command);
|
|
3837
4084
|
this.commands.push(command);
|
|
3838
4085
|
}
|
|
@@ -3877,6 +4124,24 @@ function apply(doc, command) {
|
|
|
3877
4124
|
map.ensureMergeableMap("changes").set(command.token, true);
|
|
3878
4125
|
break;
|
|
3879
4126
|
}
|
|
4127
|
+
case "field": {
|
|
4128
|
+
const map = workspace(doc, command.root);
|
|
4129
|
+
if (command.path[0] === "baseEntityIds") {
|
|
4130
|
+
const before = { baseEntityIds: bases(map).map((id) => currentId(doc, id)) };
|
|
4131
|
+
if (command.change.op === "list.move") throw new Error("Composition bases are unordered; list.move is not applicable");
|
|
4132
|
+
writeBases(doc, map, baseIds(applyFieldChanges(before, [command.change])));
|
|
4133
|
+
} else {
|
|
4134
|
+
applyNativeFieldChange(requireMap(map, "content"), command.path, command.change);
|
|
4135
|
+
map.ensureMergeableMap("changes").set(command.token, true);
|
|
4136
|
+
}
|
|
4137
|
+
break;
|
|
4138
|
+
}
|
|
4139
|
+
case "relation-field": {
|
|
4140
|
+
const map = section(doc, "relations").get(command.root);
|
|
4141
|
+
if (!(map instanceof LoroMap) || map.get("deleted") === true) throw new Error("Unknown relation");
|
|
4142
|
+
applyNativeFieldChange(map, command.path, command.change);
|
|
4143
|
+
break;
|
|
4144
|
+
}
|
|
3880
4145
|
case "delete":
|
|
3881
4146
|
workspace(doc, command.root).set("deleted", true);
|
|
3882
4147
|
break;
|
|
@@ -4284,4 +4549,4 @@ function createPlainMemoryAdapter(document, options) {
|
|
|
4284
4549
|
return new PlainMemoryAdapter(document, options);
|
|
4285
4550
|
}
|
|
4286
4551
|
//#endregion
|
|
4287
|
-
export {
|
|
4552
|
+
export { cascadeAfterVideoClipChanges as $, selectAudioScriptSegments as A, derivePositionFromAbs as B, decodeEntityRelationRows as C, assemblePhoneticScriptContent as D, assembleEntityContent as E, createRelationId as F, validateVideoDocument as G, toVideoDocument as H, hasSequence as I, LANE_KINDS_IN_STACK_ORDER as J, partUnionSchema as K, isMediaAssetVariantKind as L, variantBaseEntityIds as M, isJsonObject as N, assembleScriptText as O, createEntityId as P, solveVideoDocument as Q, buildInitialVideoDocument as R, EntityTimelineProjectionError as S, assembleCaptionContent as T, VideoDocumentValidationError as U, fromVideoDocument as V, assertValidVideoDocument as W, findLaneTrack as X, ensureLaneTrack as Y, laneTrackId as Z, assertFieldChanges as _, recordEntries as _t, applyEntityTimelineProjection as a, resolveSpeechOverlapByShiftingVideos as at, EntityProjectionGraph as b, bytesToBase64 as bt, writeVideoDocumentToDraft as c, isEmptyVideoClip as ct, LoroEntityDocument as d, DEFAULT_UNIT_TIME_MS as dt, arrangeMainTrackSeamlessly as et, LoroEntityDraft as f, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION as ft, applyFieldChanges as g, partUnionToDraft as gt, equalJson as h, speedOf as ht, MirrorVideoDocumentAdapter as i, resolveAllSpeechOverlaps as it, updateEntityFields as j, findComposedAudioScript as k, readVideoDocumentFromDraft as l, partDurationMs as lt, entityOrderGroups as m, effectiveVideoClipDurationMs as mt, createPlainMemoryAdapter as n, reassignSpeechesToVideoClipsByTime as nt, createMirrorVideoDocument as o, syncAggregatedClipsTimePosition as ot, readEntityDocument as p, VIDEO_DOCUMENT_SCHEMA_VERSION as pt, videoDocumentSchema as q, generatePartId as r, recalculateTimelineDuration as rt, createMirrorVideoDocumentAdapter as s, TIMELINE_SKELETON_DURATION_MS as st, PlainMemoryAdapter as t, fillMainTrackTimeGaps as tt, LORO_ENTITY_SCHEMA as u, safeDurationMs as ut, resolveFieldPath as v, videoDocumentMirrorSchema as vt, ScriptCompositionError as w, resolveEntityTimelineLayout as x, projectEntityTimeline as y, base64ToBytes as yt, buildSpeechHostMap as z };
|
|
@@ -493,7 +493,15 @@ type SpeechPart = Omit<SpeechPart$1, 'duration_ms'> & {
|
|
|
493
493
|
* (AudioScript provenance) and Voice alignment are entity Relations, decoupled
|
|
494
494
|
* from this display-side legacy view.
|
|
495
495
|
*/
|
|
496
|
+
/** Derived render interval, relative to the placed Caption Clip; never an Entity. */
|
|
497
|
+
interface CaptionDisplayCue {
|
|
498
|
+
segmentId: string;
|
|
499
|
+
text: string;
|
|
500
|
+
startMs: number;
|
|
501
|
+
durationMs: number;
|
|
502
|
+
}
|
|
496
503
|
type CaptionPart = Omit<CaptionPart$1, 'duration_ms'> & {
|
|
504
|
+
display_cues?: CaptionDisplayCue[];
|
|
497
505
|
initial_duration_ms?: number | undefined;
|
|
498
506
|
};
|
|
499
507
|
/**
|
|
@@ -1767,4 +1775,4 @@ declare const videoDocumentSchema: z.ZodObject<{
|
|
|
1767
1775
|
}, z.core.$loose>]>>>;
|
|
1768
1776
|
}, z.core.$loose>;
|
|
1769
1777
|
//#endregion
|
|
1770
|
-
export { SequenceRange as $, generatePartId as A,
|
|
1778
|
+
export { SequenceRange as $, generatePartId as A, VideoDraft as At, ResolvedEntityClipPlacement as B, Track$1 as Bt, PlannedSemanticOpKind as C, TrackItemTimePosition as Ct, SnapshotReadable as D, VideoDocumentSchemaVersion as Dt, SchemaValidator as E, VideoDocument as Et, videoDocumentMirrorSchema as F, CaptionPart$1 as Ft, EntityTimelineProjectionError as G, ResolvedEntityTrack as H, VideoDocumentValidationError as I, CaptionStyle as It, RelationRow as J, EntityRelationRows as K, assertValidVideoDocument as L, PartAggregation as Lt, TrackItemDraft as M, effectiveVideoClipDurationMs as Mt, VideoDocumentDraft as N, speedOf as Nt, ValidationError as O, VideoDocumentValidationIssue as Ot, VideoDocumentMirrorSchema as P, Attachment as Pt, SequenceDuration as Q, validateVideoDocument as R, SpeedShift as Rt, ImplementedSemanticOpKind as S, TrackItem as St, isImplementedSemanticOpKind as T, VideoClipPart as Tt, resolveEntityTimelineLayout as U, ResolvedEntityTimelineLayout as V, TrackItem$1 as Vt, projectEntityTimeline as W, CaptionStyleFields as X, CaptionSegmentSelection as Y, ScriptTextSegment as Z, SemanticEditor as _, PartKind as _t, PlainMemoryAdapter as a, buildInitialVideoDocument as at, TransactAudit as b, Timeline as bt, MirrorVideoDocumentAdapter as c, buildSpeechHostMap as ct, createMirrorVideoDocument as d, toVideoDocument as dt, VoiceDescriptor as et, createMirrorVideoDocumentAdapter as f, BgmPart as ft, SemanticDocumentAdapter as g, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION as gt, OpActor as h, DEFAULT_UNIT_TIME_MS as ht, JournalEntry as i, InitialDocumentFacts as it, TrackDraft as j, VideoDraftPartUnion as jt, PartIdFactory as k, VideoDocumentValidationIssueCode as kt, MirrorVideoDocumentOptions as l, derivePositionFromAbs as lt, CommitOptions as m, CaptionPart as mt, videoDocumentSchema as n, JsonValue as nt, PlainMemoryAdapterOptions as o, DerivedItemPosition as ot, writeVideoDocumentToDraft as p, CaptionDisplayCue as pt, EntityRow as q, readVideoDocumentFromDraft as r, EntityId as rt, createPlainMemoryAdapter as s, SpeechHostMap as st, partUnionSchema as t, JsonObject as tt, applyEntityTimelineProjection as u, fromVideoDocument as ut, SemanticOpInput as v, PartUnion as vt, SemanticOpKind as w, VIDEO_DOCUMENT_SCHEMA_VERSION as wt, IMPLEMENTED_SEMANTIC_OP_KINDS as x, Track as xt, SemanticOpName as y, SpeechPart as yt, EntityTimelineTrackRole as z, Timeline$1 as zt };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as index_d_exports } from "./index-CMa6ZCtX.js";
|
|
2
|
-
import { $ as SequenceRange, A as generatePartId, At as
|
|
2
|
+
import { $ as SequenceRange, A as generatePartId, At as VideoDraft, B as ResolvedEntityClipPlacement, Bt as Track$1, C as PlannedSemanticOpKind, Ct as TrackItemTimePosition, D as SnapshotReadable, Dt as VideoDocumentSchemaVersion, E as SchemaValidator, Et as VideoDocument, F as videoDocumentMirrorSchema, Ft as CaptionPart$1, G as EntityTimelineProjectionError, H as ResolvedEntityTrack, I as VideoDocumentValidationError, It as CaptionStyle, J as RelationRow, K as EntityRelationRows, L as assertValidVideoDocument, Lt as PartAggregation, M as TrackItemDraft, Mt as effectiveVideoClipDurationMs, N as VideoDocumentDraft, Nt as speedOf, O as ValidationError, Ot as VideoDocumentValidationIssue, P as VideoDocumentMirrorSchema, Pt as Attachment, Q as SequenceDuration, R as validateVideoDocument, Rt as SpeedShift, S as ImplementedSemanticOpKind, St as TrackItem, T as isImplementedSemanticOpKind, Tt as VideoClipPart, U as resolveEntityTimelineLayout, V as ResolvedEntityTimelineLayout, Vt as TrackItem$1, W as projectEntityTimeline, X as CaptionStyleFields, Y as CaptionSegmentSelection, Z as ScriptTextSegment, _ as SemanticEditor, _t as PartKind, a as PlainMemoryAdapter, at as buildInitialVideoDocument, b as TransactAudit, bt as Timeline, c as MirrorVideoDocumentAdapter, ct as buildSpeechHostMap, d as createMirrorVideoDocument, dt as toVideoDocument, et as VoiceDescriptor, f as createMirrorVideoDocumentAdapter, ft as BgmPart, g as SemanticDocumentAdapter, gt as ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, h as OpActor, ht as DEFAULT_UNIT_TIME_MS, i as JournalEntry, it as InitialDocumentFacts, j as TrackDraft, jt as VideoDraftPartUnion, k as PartIdFactory, kt as VideoDocumentValidationIssueCode, l as MirrorVideoDocumentOptions, lt as derivePositionFromAbs, m as CommitOptions, mt as CaptionPart, n as videoDocumentSchema, nt as JsonValue, o as PlainMemoryAdapterOptions, ot as DerivedItemPosition, p as writeVideoDocumentToDraft, pt as CaptionDisplayCue, q as EntityRow, r as readVideoDocumentFromDraft, rt as EntityId, s as createPlainMemoryAdapter, st as SpeechHostMap, t as partUnionSchema, tt as JsonObject, u as applyEntityTimelineProjection, ut as fromVideoDocument, v as SemanticOpInput, vt as PartUnion, w as SemanticOpKind, wt as VIDEO_DOCUMENT_SCHEMA_VERSION, x as IMPLEMENTED_SEMANTIC_OP_KINDS, xt as Track, y as SemanticOpName, yt as SpeechPart, z as EntityTimelineTrackRole, zt as Timeline$1 } from "./index-D5XV4UPC.js";
|
|
3
3
|
import { LoroDoc, PeerID } from "loro-crdt";
|
|
4
4
|
import { DocState } from "@mengine/sync";
|
|
5
5
|
import { BaseDocStorage, Connection, DocDiff, DocPushReceipt, DocSnapshotRecord, DocStorage, DocStorageOptions, DocUpdate, DocUpdateRecord } from "@mengine/storage";
|
|
@@ -624,7 +624,7 @@ declare function assertCanonicalEditorResources(rows: EntityRelationRows): void;
|
|
|
624
624
|
*/
|
|
625
625
|
declare function assertMediaAssetWritePolicy(before: EntityRelationRows, after: EntityRelationRows): void;
|
|
626
626
|
/** Add only missing editor structure; existing identities and owned settings are never replaced. */
|
|
627
|
-
declare function ensureEditorFoundation(initial: EntityRelationRows, idFactory?: EntityTimelineIdFactory, timelinePayload?: EntityRow['payload']): EditorFoundation;
|
|
627
|
+
declare function ensureEditorFoundation(initial: EntityRelationRows, idFactory?: EntityTimelineIdFactory, timelinePayload?: EntityRow['payload'], selectedAudioScriptEntityId?: string | null): EditorFoundation;
|
|
628
628
|
//#endregion
|
|
629
629
|
//#region src/entity-editor/media-asset-import.d.ts
|
|
630
630
|
interface ImportedMediaAsset {
|
|
@@ -676,6 +676,45 @@ interface DocumentAudioScriptState {
|
|
|
676
676
|
/** Read only the attached version and preserve every segment; never aggregate other scripts. */
|
|
677
677
|
declare function readDocumentAudioScript(state: DocumentAudioScriptState): DocumentAudioScript;
|
|
678
678
|
//#endregion
|
|
679
|
+
//#region src/entity-crdt/field-changes.d.ts
|
|
680
|
+
/** List members are addressed by identity, never a transient array offset. */
|
|
681
|
+
type FieldPath = readonly (string | {
|
|
682
|
+
elementId: string;
|
|
683
|
+
})[];
|
|
684
|
+
type FieldChange = {
|
|
685
|
+
op: 'set';
|
|
686
|
+
path: FieldPath;
|
|
687
|
+
value: JsonValue;
|
|
688
|
+
} | {
|
|
689
|
+
op: 'unset';
|
|
690
|
+
path: FieldPath;
|
|
691
|
+
} | {
|
|
692
|
+
op: 'text.splice';
|
|
693
|
+
path: FieldPath;
|
|
694
|
+
index: number;
|
|
695
|
+
deleteCount: number;
|
|
696
|
+
text: string;
|
|
697
|
+
} | {
|
|
698
|
+
op: 'list.insert';
|
|
699
|
+
path: FieldPath;
|
|
700
|
+
value: JsonValue;
|
|
701
|
+
beforeElementId: string | null;
|
|
702
|
+
} | {
|
|
703
|
+
op: 'list.move';
|
|
704
|
+
path: FieldPath;
|
|
705
|
+
elementId: string;
|
|
706
|
+
beforeElementId: string | null;
|
|
707
|
+
} | {
|
|
708
|
+
op: 'list.remove';
|
|
709
|
+
path: FieldPath;
|
|
710
|
+
elementId: string;
|
|
711
|
+
};
|
|
712
|
+
declare function assertFieldChanges(changes: readonly FieldChange[]): void;
|
|
713
|
+
/** Resolve against the sequential causal view; the numeric path never crosses the API boundary. */
|
|
714
|
+
declare function resolveFieldPath(payload: JsonObject, path: FieldPath): (string | number)[];
|
|
715
|
+
/** Detached plan evaluation. Native compilation replays the original operations, not this snapshot. */
|
|
716
|
+
declare function applyFieldChanges(payload: JsonObject, changes: readonly FieldChange[]): JsonObject;
|
|
717
|
+
//#endregion
|
|
679
718
|
//#region src/entity-crdt/entity-document.d.ts
|
|
680
719
|
declare const LORO_ENTITY_SCHEMA = "medeo.entities.loro.v1";
|
|
681
720
|
interface EntityDocumentState {
|
|
@@ -707,6 +746,17 @@ type Command = {
|
|
|
707
746
|
deleteCount: number;
|
|
708
747
|
text: string;
|
|
709
748
|
token: string;
|
|
749
|
+
} | {
|
|
750
|
+
type: 'field';
|
|
751
|
+
root: string;
|
|
752
|
+
path: (string | number)[];
|
|
753
|
+
change: FieldChange;
|
|
754
|
+
token: string;
|
|
755
|
+
} | {
|
|
756
|
+
type: 'relation-field';
|
|
757
|
+
root: string;
|
|
758
|
+
path: (string | number)[];
|
|
759
|
+
change: FieldChange;
|
|
710
760
|
} | {
|
|
711
761
|
type: 'delete';
|
|
712
762
|
root: string;
|
|
@@ -754,9 +804,12 @@ declare class LoroEntityDraft {
|
|
|
754
804
|
private readonly doc;
|
|
755
805
|
readonly commands: Command[];
|
|
756
806
|
private readonly selectedRoots;
|
|
807
|
+
private readonly relationAliases;
|
|
757
808
|
constructor(doc: LoroDoc);
|
|
758
809
|
snapshot(): EntityDocumentState;
|
|
759
810
|
order(groupId: string, entityIds: readonly string[]): void;
|
|
811
|
+
/** Project the final scalar placement intents onto the existing native ordering containers. */
|
|
812
|
+
reconcileOrder(rows: EntityRelationRows): void;
|
|
760
813
|
create(row: EntityRow): void;
|
|
761
814
|
delete(entityId: string): void;
|
|
762
815
|
attach(slot: string, entityId: string): void;
|
|
@@ -768,6 +821,9 @@ declare class LoroEntityDraft {
|
|
|
768
821
|
declare(entityId: string, fields: JsonObject): void;
|
|
769
822
|
replaceOwned(entityId: string, payload: JsonObject): void;
|
|
770
823
|
editText(entityId: string, path: readonly (string | number)[], start: number, deleteCount: number, text: string): void;
|
|
824
|
+
/** Generic assembled-field edit compiled at the author's causal position. */
|
|
825
|
+
change(entityId: string, changes: readonly FieldChange[]): void;
|
|
826
|
+
changeRelation(relationId: string, changes: readonly FieldChange[]): void;
|
|
771
827
|
captureSelectionBaselines(): void;
|
|
772
828
|
private record;
|
|
773
829
|
}
|
|
@@ -1688,4 +1744,4 @@ declare function hostForAbsMs(ranges: MainClipRange[], absMs: number): MainClipR
|
|
|
1688
1744
|
*/
|
|
1689
1745
|
declare function relativePositionForAbs(ranges: MainClipRange[], absMs: number): TrackItemTimePosition;
|
|
1690
1746
|
//#endregion
|
|
1691
|
-
export { type Aggregation, type AssembledCaptionContent, type AssembledPhoneticScriptContent, type Attachment, type AudioMediaAssetFact, type BgmPart, type CaptionContentInput, type CaptionPart, type CaptionSegmentSelection, type CaptionStyle, type ClipEntityId, type ClipPlacement, type CommitOptions, DEFAULT_UNIT_TIME_MS, type DeleteBgmInput, type DeleteClipInput, type DeleteClipTreeInput, type DeleteVoiceoverInput, type DerivedItemPosition, type DocStorageLike, type DocVersionMark, type DocumentAudioScript, type DocumentAudioScriptState, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, type EditorFoundation, EntityDocumentState, type EntityGraphCommitOptions, EntityGraphHttpClient, type EntityGraphState, EntityTimelineEditor, type EntityTimelineIdFactory, EntityTimelineProjectionError, type EntityTimelineTrackRole, IMPLEMENTED_SEMANTIC_OP_KINDS, type ImageMediaAssetFact, type ImplementedSemanticOpKind, type ImportedMediaAsset, type InitialDocumentFacts, type InsertCaptionClipInput, type InsertClipInput, type InsertMediaClipInput, type InsertMediaClipsInput, type InsertPlacedClipInput, type JournalEntry, LANE_KINDS_IN_STACK_ORDER, LORO_ENTITY_SCHEMA, type LaneKind, type LinearClipSpeed, LoroEntityDocument, LoroEntityDraft, type MainClipRange, type MakeEmptyPart, ManualSyncDoc, type ManualSyncDocOptions, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type MediaAssetFact, type MediaClipInsertion, MemoryDocStorage, MengineAckFailedError, type MengineAuditEntry, type MengineAuditResponse, MengineDocSession, type MengineDocSessionOptions, type MengineDocSessionUpdateEvent, type MengineDocumentVersion, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUpdateMeta, MirrorVideoDocumentAdapter, type MirrorVideoDocumentOptions, type MoveClipInput, type MoveClipsToStartsInput, type MoveSequentialClipsInput, type MoveVoiceoverInput, type OpActor, type PartAggregation, type PartIdFactory, type PartKind, type PartUnion, type PatchCaptionStyleInput, PlainMemoryAdapter, type PlainMemoryAdapterOptions, type PlannedSemanticOpKind, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, type ReplaceClipContentInput, type ReplaceMediaClipInput, type ReplaceSequentialClipsInput, type ReplacementMediaClipInput, type ResolvedEntityClipPlacement, type ResolvedEntityTimelineLayout, type ResolvedEntityTrack, SchemaValidator, ScriptCompositionError, type SemanticDocumentAdapter, SemanticEditor, type SemanticOpInput, type SemanticOpKind, type SemanticOpName, type SequentialClipAnchor, type SetBgmInput, type SetCaptionVisibilityInput, type SetClipPlacementInput, type SetClipSpeedInput, type SetClipVolumeInput, type SnapshotReadable, type SolvedVideoDocument, type SpeechHostMap, type SpeechPart, type SpeedShift, TIMELINE_SKELETON_DURATION_MS, type Timeline, type TimelineDoc, type TimelineItem, type Track, type TrackDraft, type TrackItem, type TrackItemDraft, type TrackItemTimePosition, type TransactAudit, type TrimClipInput, type UpdateClipInput, type UpdateClipMarkerInput, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, type VideoClipPart, type VideoDocument, type VideoDocumentDraft, type VideoDocumentMirrorSchema, type VideoDocumentSchemaVersion, VideoDocumentValidationError, type VideoDocumentValidationIssue, type VideoDocumentValidationIssueCode, type VideoDraft, type CaptionPart$1 as VideoDraftCaptionPart, type VideoDraftPartUnion, type Timeline$1 as VideoDraftTimeline, type Track$1 as VideoDraftTrack, type TrackItem$1 as VideoDraftTrackItem, type VideoMediaAssetFact, type VisualMediaAssetFact, type VoiceMediaAssetFact, type VoiceoverCaptionFact, type VoiceoverTakeInput, type VoiceoverTakeResult, type WaitForServerAckOptions, applyEntityRows, applyEntityTimelineProjection, arrangeMainTrackSeamlessly, assembleCaptionContent, assembleEntityContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, compileEntityRows, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, prepareCaptionContent, projectEntityTimeline, readDocumentAudioScript, readEntityDocument, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveSpeechOverlapByShiftingVideos, safeDurationMs, index_d_exports as schemas, selectAudioScriptSegments, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
|
1747
|
+
export { type Aggregation, type AssembledCaptionContent, type AssembledPhoneticScriptContent, type Attachment, type AudioMediaAssetFact, type BgmPart, type CaptionContentInput, type CaptionDisplayCue, type CaptionPart, type CaptionSegmentSelection, type CaptionStyle, type ClipEntityId, type ClipPlacement, type CommitOptions, DEFAULT_UNIT_TIME_MS, type DeleteBgmInput, type DeleteClipInput, type DeleteClipTreeInput, type DeleteVoiceoverInput, type DerivedItemPosition, type DocStorageLike, type DocVersionMark, type DocumentAudioScript, type DocumentAudioScriptState, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, type EditorFoundation, EntityDocumentState, type EntityGraphCommitOptions, EntityGraphHttpClient, type EntityGraphState, EntityTimelineEditor, type EntityTimelineIdFactory, EntityTimelineProjectionError, type EntityTimelineTrackRole, type FieldChange, type FieldPath, IMPLEMENTED_SEMANTIC_OP_KINDS, type ImageMediaAssetFact, type ImplementedSemanticOpKind, type ImportedMediaAsset, type InitialDocumentFacts, type InsertCaptionClipInput, type InsertClipInput, type InsertMediaClipInput, type InsertMediaClipsInput, type InsertPlacedClipInput, type JournalEntry, LANE_KINDS_IN_STACK_ORDER, LORO_ENTITY_SCHEMA, type LaneKind, type LinearClipSpeed, LoroEntityDocument, LoroEntityDraft, type MainClipRange, type MakeEmptyPart, ManualSyncDoc, type ManualSyncDocOptions, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type MediaAssetFact, type MediaClipInsertion, MemoryDocStorage, MengineAckFailedError, type MengineAuditEntry, type MengineAuditResponse, MengineDocSession, type MengineDocSessionOptions, type MengineDocSessionUpdateEvent, type MengineDocumentVersion, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUpdateMeta, MirrorVideoDocumentAdapter, type MirrorVideoDocumentOptions, type MoveClipInput, type MoveClipsToStartsInput, type MoveSequentialClipsInput, type MoveVoiceoverInput, type OpActor, type PartAggregation, type PartIdFactory, type PartKind, type PartUnion, type PatchCaptionStyleInput, PlainMemoryAdapter, type PlainMemoryAdapterOptions, type PlannedSemanticOpKind, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, type ReplaceClipContentInput, type ReplaceMediaClipInput, type ReplaceSequentialClipsInput, type ReplacementMediaClipInput, type ResolvedEntityClipPlacement, type ResolvedEntityTimelineLayout, type ResolvedEntityTrack, SchemaValidator, ScriptCompositionError, type SemanticDocumentAdapter, SemanticEditor, type SemanticOpInput, type SemanticOpKind, type SemanticOpName, type SequentialClipAnchor, type SetBgmInput, type SetCaptionVisibilityInput, type SetClipPlacementInput, type SetClipSpeedInput, type SetClipVolumeInput, type SnapshotReadable, type SolvedVideoDocument, type SpeechHostMap, type SpeechPart, type SpeedShift, TIMELINE_SKELETON_DURATION_MS, type Timeline, type TimelineDoc, type TimelineItem, type Track, type TrackDraft, type TrackItem, type TrackItemDraft, type TrackItemTimePosition, type TransactAudit, type TrimClipInput, type UpdateClipInput, type UpdateClipMarkerInput, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, type VideoClipPart, type VideoDocument, type VideoDocumentDraft, type VideoDocumentMirrorSchema, type VideoDocumentSchemaVersion, VideoDocumentValidationError, type VideoDocumentValidationIssue, type VideoDocumentValidationIssueCode, type VideoDraft, type CaptionPart$1 as VideoDraftCaptionPart, type VideoDraftPartUnion, type Timeline$1 as VideoDraftTimeline, type Track$1 as VideoDraftTrack, type TrackItem$1 as VideoDraftTrackItem, type VideoMediaAssetFact, type VisualMediaAssetFact, type VoiceMediaAssetFact, type VoiceoverCaptionFact, type VoiceoverTakeInput, type VoiceoverTakeResult, type WaitForServerAckOptions, applyEntityRows, applyEntityTimelineProjection, applyFieldChanges, arrangeMainTrackSeamlessly, assembleCaptionContent, assembleEntityContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertFieldChanges, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, compileEntityRows, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, prepareCaptionContent, projectEntityTimeline, readDocumentAudioScript, readEntityDocument, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveFieldPath, resolveSpeechOverlapByShiftingVideos, safeDurationMs, index_d_exports as schemas, selectAudioScriptSegments, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as cascadeAfterVideoClipChanges, A as selectAudioScriptSegments, B as derivePositionFromAbs, C as decodeEntityRelationRows, D as assemblePhoneticScriptContent, E as assembleEntityContent, F as createRelationId, G as validateVideoDocument, H as toVideoDocument, I as hasSequence, J as LANE_KINDS_IN_STACK_ORDER, K as partUnionSchema, L as isMediaAssetVariantKind, M as variantBaseEntityIds, N as isJsonObject, O as assembleScriptText, P as createEntityId, Q as solveVideoDocument, R as buildInitialVideoDocument, S as EntityTimelineProjectionError, T as assembleCaptionContent, U as VideoDocumentValidationError, V as fromVideoDocument, W as assertValidVideoDocument, X as findLaneTrack, Y as ensureLaneTrack, Z as laneTrackId, _ as assertFieldChanges, _t as recordEntries, a as applyEntityTimelineProjection, at as resolveSpeechOverlapByShiftingVideos, b as EntityProjectionGraph, bt as bytesToBase64, c as writeVideoDocumentToDraft, ct as isEmptyVideoClip, d as LoroEntityDocument, dt as DEFAULT_UNIT_TIME_MS, et as arrangeMainTrackSeamlessly, f as LoroEntityDraft, ft as ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, g as applyFieldChanges, gt as partUnionToDraft, h as equalJson, ht as speedOf, i as MirrorVideoDocumentAdapter, it as resolveAllSpeechOverlaps, j as updateEntityFields, k as findComposedAudioScript, l as readVideoDocumentFromDraft, lt as partDurationMs, m as entityOrderGroups, mt as effectiveVideoClipDurationMs, n as createPlainMemoryAdapter, nt as reassignSpeechesToVideoClipsByTime, o as createMirrorVideoDocument, ot as syncAggregatedClipsTimePosition, p as readEntityDocument, pt as VIDEO_DOCUMENT_SCHEMA_VERSION, q as videoDocumentSchema, r as generatePartId, rt as recalculateTimelineDuration, s as createMirrorVideoDocumentAdapter, st as TIMELINE_SKELETON_DURATION_MS, t as PlainMemoryAdapter, tt as fillMainTrackTimeGaps, u as LORO_ENTITY_SCHEMA, ut as safeDurationMs, v as resolveFieldPath, vt as videoDocumentMirrorSchema, w as ScriptCompositionError, x as resolveEntityTimelineLayout, y as projectEntityTimeline, yt as base64ToBytes, z as buildSpeechHostMap } from "./document-BLm4ABAb.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";
|
|
@@ -362,9 +362,13 @@ function memotaLocator(value) {
|
|
|
362
362
|
* explicit project attachment, multiple candidates are ambiguous. Existing
|
|
363
363
|
* content IDs are reused here; Loro editing advances their immutable versions.
|
|
364
364
|
*/
|
|
365
|
-
function ensureDocumentAudioScript(entities, idFactory) {
|
|
365
|
+
function ensureDocumentAudioScript(entities, idFactory, selectedEntityId) {
|
|
366
|
+
if (selectedEntityId != null) {
|
|
367
|
+
if (!entities.some((row) => row.entityKind === "audio-script" && row.entityId === selectedEntityId)) throw new EntityTimelineProjectionError(`Selected AudioScript ${selectedEntityId} does not exist`);
|
|
368
|
+
return selectedEntityId;
|
|
369
|
+
}
|
|
366
370
|
const scripts = entities.filter((row) => row.entityKind === "audio-script");
|
|
367
|
-
if (scripts.length > 1) throw new EntityTimelineProjectionError("
|
|
371
|
+
if (scripts.length > 1) throw new EntityTimelineProjectionError("Select an AudioScript for the editor panel when multiple scripts exist");
|
|
368
372
|
const existing = scripts[0];
|
|
369
373
|
if (existing !== void 0) return existing.entityId;
|
|
370
374
|
const id = createEntityId(idFactory("entity"));
|
|
@@ -377,7 +381,7 @@ function ensureDocumentAudioScript(entities, idFactory) {
|
|
|
377
381
|
return id;
|
|
378
382
|
}
|
|
379
383
|
/** Add only missing editor structure; existing identities and owned settings are never replaced. */
|
|
380
|
-
function ensureEditorFoundation(initial, idFactory = (prefix) => `${prefix}_${globalThis.crypto.randomUUID()}`, timelinePayload = {}) {
|
|
384
|
+
function ensureEditorFoundation(initial, idFactory = (prefix) => `${prefix}_${globalThis.crypto.randomUUID()}`, timelinePayload = {}, selectedAudioScriptEntityId) {
|
|
381
385
|
const entities = structuredClone([...initial.entities]);
|
|
382
386
|
const relations = structuredClone([...initial.relations]);
|
|
383
387
|
const roots = entities.filter((row) => row.entityKind === "timeline");
|
|
@@ -428,7 +432,7 @@ function ensureEditorFoundation(initial, idFactory = (prefix) => `${prefix}_${gl
|
|
|
428
432
|
}
|
|
429
433
|
trackEntityIds[role] = track.entityId;
|
|
430
434
|
}
|
|
431
|
-
const audioScriptEntityId = ensureDocumentAudioScript(entities, idFactory);
|
|
435
|
+
const audioScriptEntityId = ensureDocumentAudioScript(entities, idFactory, selectedAudioScriptEntityId);
|
|
432
436
|
return {
|
|
433
437
|
rows: {
|
|
434
438
|
entities,
|
|
@@ -4848,4 +4852,4 @@ function serverCovers(serverVV, target) {
|
|
|
4848
4852
|
return covers(server, target);
|
|
4849
4853
|
}
|
|
4850
4854
|
//#endregion
|
|
4851
|
-
export { DEFAULT_UNIT_TIME_MS, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, EntityGraphHttpClient, EntityTimelineEditor, EntityTimelineProjectionError, IMPLEMENTED_SEMANTIC_OP_KINDS, LANE_KINDS_IN_STACK_ORDER, LORO_ENTITY_SCHEMA, LoroEntityDocument, LoroEntityDraft, ManualSyncDoc, MedeoHttpDocStorage, MemoryDocStorage, MengineAckFailedError, MengineDocSession, MengineHttpClient, MengineHttpRequestError, MenginePushRejectedError, MirrorVideoDocumentAdapter, PlainMemoryAdapter, SchemaValidator, ScriptCompositionError, SemanticEditor, TIMELINE_SKELETON_DURATION_MS, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, VideoDocumentValidationError, applyEntityRows, applyEntityTimelineProjection, arrangeMainTrackSeamlessly, assembleCaptionContent, assembleEntityContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, compileEntityRows, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, prepareCaptionContent, projectEntityTimeline, readDocumentAudioScript, readEntityDocument, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveSpeechOverlapByShiftingVideos, safeDurationMs, schemas_exports as schemas, selectAudioScriptSegments, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
|
4855
|
+
export { DEFAULT_UNIT_TIME_MS, ENTITY_TIMELINE_PROJECTION_SCHEMA_VERSION, EntityGraphHttpClient, EntityTimelineEditor, EntityTimelineProjectionError, IMPLEMENTED_SEMANTIC_OP_KINDS, LANE_KINDS_IN_STACK_ORDER, LORO_ENTITY_SCHEMA, LoroEntityDocument, LoroEntityDraft, ManualSyncDoc, MedeoHttpDocStorage, MemoryDocStorage, MengineAckFailedError, MengineDocSession, MengineHttpClient, MengineHttpRequestError, MenginePushRejectedError, MirrorVideoDocumentAdapter, PlainMemoryAdapter, SchemaValidator, ScriptCompositionError, SemanticEditor, TIMELINE_SKELETON_DURATION_MS, VIDEO_DOCUMENT_SCHEMA_VERSION, ValidationError, VideoDocumentValidationError, applyEntityRows, applyEntityTimelineProjection, applyFieldChanges, arrangeMainTrackSeamlessly, assembleCaptionContent, assembleEntityContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertFieldChanges, assertMediaAssetWritePolicy, assertValidVideoDocument, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, compileEntityRows, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, prepareCaptionContent, projectEntityTimeline, readDocumentAudioScript, readEntityDocument, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveFieldPath, resolveSpeechOverlapByShiftingVideos, safeDurationMs, schemas_exports as schemas, selectAudioScriptSegments, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema, writeVideoDocumentToDraft };
|
package/dist/testing.d.ts
CHANGED
package/dist/testing.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { bt as bytesToBase64, pt as VIDEO_DOCUMENT_SCHEMA_VERSION, s as createMirrorVideoDocumentAdapter, yt as base64ToBytes } from "./document-BLm4ABAb.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.4.1-alpha.
|
|
3
|
+
"version": "1.4.1-alpha.4",
|
|
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.4.1-alpha.
|
|
32
|
-
"@mengine/
|
|
33
|
-
"@mengine/
|
|
31
|
+
"@mengine/storage": "1.4.1-alpha.4",
|
|
32
|
+
"@mengine/sync": "1.4.1-alpha.4",
|
|
33
|
+
"@mengine/utils": "1.4.1-alpha.4"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^25.9.1",
|