@mengine/medeo-client 1.2.1-alpha.0 → 1.2.1-alpha.1
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/dist/{document-49OdvviW.js → document-Dcu87api.js} +22 -126
- package/dist/{index-BO2fSUKi.d.ts → index-CZlTzzrm.d.ts} +624 -105
- package/dist/index.d.ts +25 -28
- package/dist/index.js +605 -135
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -40
- package/package.json +4 -7
- package/dist/index-InEWX9rk.d.ts +0 -609
- package/dist/schemas.d.ts +0 -2
- package/dist/schemas.js +0 -518
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Mirror, schema } from "loro-mirror";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { LoroDoc } from "loro-crdt";
|
|
4
|
-
import { produce } from "immer";
|
|
5
4
|
//#region src/client/base64.ts
|
|
6
5
|
function bytesToBase64(bytes) {
|
|
7
6
|
let binary = "";
|
|
@@ -88,7 +87,8 @@ function jsonTransform() {
|
|
|
88
87
|
const trackItem = schema.LoroMap({
|
|
89
88
|
part_id: schema.String(),
|
|
90
89
|
time_position: schema.String().transform(jsonTransform()),
|
|
91
|
-
fallback_abs_ms: schema.Number({ required: false })
|
|
90
|
+
fallback_abs_ms: schema.Number({ required: false }),
|
|
91
|
+
duration_override_ms: schema.Number({ required: false })
|
|
92
92
|
});
|
|
93
93
|
const track = schema.LoroMap({
|
|
94
94
|
id: schema.String(),
|
|
@@ -774,7 +774,8 @@ const trackItemTimePositionSchema = z.discriminatedUnion("mode", [
|
|
|
774
774
|
const trackItemSchema = z.object({
|
|
775
775
|
part_id: z.string(),
|
|
776
776
|
time_position: trackItemTimePositionSchema,
|
|
777
|
-
fallback_abs_ms: finiteNumber.optional()
|
|
777
|
+
fallback_abs_ms: finiteNumber.optional(),
|
|
778
|
+
duration_override_ms: z.number().finite().positive().optional()
|
|
778
779
|
}).passthrough();
|
|
779
780
|
const trackSchema = z.object({
|
|
780
781
|
id: z.string().optional(),
|
|
@@ -1327,7 +1328,7 @@ function fromVideoDocument(document) {
|
|
|
1327
1328
|
above_main_tracks: aboveTracks.map((t) => draftTrack(t, view.absByPartId)),
|
|
1328
1329
|
below_main_tracks: belowTracks.map((t) => draftTrack(t, view.absByPartId)),
|
|
1329
1330
|
part_aggregations: view.aggregations,
|
|
1330
|
-
part_library: toReadViewPartLibrary(view.partLibrary, view.durationMs, view.derivedFillerPartIds),
|
|
1331
|
+
part_library: toReadViewPartLibrary(view.partLibrary, view.durationMs, view.derivedFillerPartIds, captionDurationOverrides(document)),
|
|
1331
1332
|
version: document.meta.version
|
|
1332
1333
|
};
|
|
1333
1334
|
}
|
|
@@ -1348,7 +1349,7 @@ function fromVideoDocument(document) {
|
|
|
1348
1349
|
* and they are not part of the document (see `fromVideoDocument`). An empty clip a
|
|
1349
1350
|
* writer placed deliberately is NOT in that set and is projected normally.
|
|
1350
1351
|
*/
|
|
1351
|
-
function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds) {
|
|
1352
|
+
function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds, captionDurationByPartId) {
|
|
1352
1353
|
const out = {};
|
|
1353
1354
|
for (const [partId, part] of Object.entries(partLibrary)) {
|
|
1354
1355
|
if (derivedFillerPartIds.has(partId)) continue;
|
|
@@ -1368,7 +1369,7 @@ function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds) {
|
|
|
1368
1369
|
const caption = clone(part.caption);
|
|
1369
1370
|
out[partId] = { caption: {
|
|
1370
1371
|
...caption,
|
|
1371
|
-
duration_ms: caption.initial_duration_ms
|
|
1372
|
+
duration_ms: captionDurationByPartId.get(partId) ?? caption.initial_duration_ms
|
|
1372
1373
|
} };
|
|
1373
1374
|
} else if (part.bgm != null) out[partId] = { bgm: {
|
|
1374
1375
|
...clone(part.bgm),
|
|
@@ -1377,6 +1378,14 @@ function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds) {
|
|
|
1377
1378
|
}
|
|
1378
1379
|
return out;
|
|
1379
1380
|
}
|
|
1381
|
+
function captionDurationOverrides(document) {
|
|
1382
|
+
const result = /* @__PURE__ */ new Map();
|
|
1383
|
+
for (const track of document.tracks ?? []) {
|
|
1384
|
+
if (track.parts_kind !== "caption") continue;
|
|
1385
|
+
for (const item of track.items ?? []) if (item.duration_override_ms != null) result.set(item.part_id, item.duration_override_ms);
|
|
1386
|
+
}
|
|
1387
|
+
return result;
|
|
1388
|
+
}
|
|
1380
1389
|
/** Deep-clone a part payload, dropping the derived read-view `duration_ms`. */
|
|
1381
1390
|
function omitDurationMs(part) {
|
|
1382
1391
|
const { duration_ms: _drop, ...rest } = clone(part);
|
|
@@ -1539,6 +1548,7 @@ function rowToTrack(row) {
|
|
|
1539
1548
|
time_position: item.time_position
|
|
1540
1549
|
};
|
|
1541
1550
|
if (item.fallback_abs_ms != null) result.fallback_abs_ms = item.fallback_abs_ms;
|
|
1551
|
+
if (item.duration_override_ms != null) result.duration_override_ms = item.duration_override_ms;
|
|
1542
1552
|
return result;
|
|
1543
1553
|
})
|
|
1544
1554
|
};
|
|
@@ -1613,7 +1623,7 @@ function createMirrorVideoDocument(document, options = {}) {
|
|
|
1613
1623
|
doc,
|
|
1614
1624
|
schema: videoDocumentMirrorSchema
|
|
1615
1625
|
}).setState((draft) => {
|
|
1616
|
-
|
|
1626
|
+
seedDraft(draft, document);
|
|
1617
1627
|
}, { origin: options.origin ?? "mengine.bootstrap" });
|
|
1618
1628
|
return doc;
|
|
1619
1629
|
}
|
|
@@ -1621,8 +1631,8 @@ function createMirrorVideoDocument(document, options = {}) {
|
|
|
1621
1631
|
function createMirrorVideoDocumentAdapter(document, options) {
|
|
1622
1632
|
return new MirrorVideoDocumentAdapter(createMirrorVideoDocument(document, options));
|
|
1623
1633
|
}
|
|
1624
|
-
/** Write a whole `VideoDocument` into
|
|
1625
|
-
function
|
|
1634
|
+
/** Write a whole `VideoDocument` into the mirror draft (used to seed a fresh doc). */
|
|
1635
|
+
function seedDraft(draft, document) {
|
|
1626
1636
|
draft.meta = {
|
|
1627
1637
|
schema_version: document.meta.schema_version,
|
|
1628
1638
|
draft_id: document.meta.draft_id ?? void 0,
|
|
@@ -1647,124 +1657,10 @@ function toTrackRow(track) {
|
|
|
1647
1657
|
items: (track.items ?? []).map((item) => ({
|
|
1648
1658
|
part_id: item.part_id,
|
|
1649
1659
|
time_position: item.time_position,
|
|
1650
|
-
fallback_abs_ms: item.fallback_abs_ms
|
|
1660
|
+
fallback_abs_ms: item.fallback_abs_ms,
|
|
1661
|
+
duration_override_ms: item.duration_override_ms
|
|
1651
1662
|
}))
|
|
1652
1663
|
};
|
|
1653
1664
|
}
|
|
1654
1665
|
//#endregion
|
|
1655
|
-
|
|
1656
|
-
/**
|
|
1657
|
-
* Part-id generation, aligned with the online ecosystem.
|
|
1658
|
-
*
|
|
1659
|
-
* The authoritative online producers — agent-harness (`@harness/shared`
|
|
1660
|
-
* `genObjId`) and director.v2 (`common/obj_id.py` `gen_obj_id`) — both mint part
|
|
1661
|
-
* ids as `` `${prefix}_${ulid()}` ``, and real captured drafts use exactly that
|
|
1662
|
-
* shape (`clip_…` / `spe_…` / `cap_…` / `bgm_…`, each a 26-char ULID). The engine
|
|
1663
|
-
* previously emitted `vc_<base36 timestamp><6 random>`, a different prefix AND a
|
|
1664
|
-
* different encoding — the sole cross-repo id divergence. This module removes it
|
|
1665
|
-
* by emitting the same `<prefix>_<ULID>` bytes.
|
|
1666
|
-
*
|
|
1667
|
-
* The ULID is generated inline (Crockford Base32, 48-bit time + 80-bit random)
|
|
1668
|
-
* rather than pulling the `ulid` npm package: the randomness class matches the
|
|
1669
|
-
* old generator (both `Math.random`-based) and it keeps `@mengine/medeo-client`
|
|
1670
|
-
* dependency-free for a purely mechanical id string. Part ids only need to be
|
|
1671
|
-
* unique and lexicographically time-sortable, which this satisfies.
|
|
1672
|
-
*/
|
|
1673
|
-
/** Crockford Base32 alphabet (no I, L, O, U), per the ULID spec. */
|
|
1674
|
-
const CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
1675
|
-
const TIME_LEN = 10;
|
|
1676
|
-
const RANDOM_LEN = 16;
|
|
1677
|
-
function encodeTime(now) {
|
|
1678
|
-
let out = "";
|
|
1679
|
-
let ms = now;
|
|
1680
|
-
for (let i = TIME_LEN - 1; i >= 0; i--) {
|
|
1681
|
-
const mod = ms % 32;
|
|
1682
|
-
out = CROCKFORD[mod] + out;
|
|
1683
|
-
ms = (ms - mod) / 32;
|
|
1684
|
-
}
|
|
1685
|
-
return out;
|
|
1686
|
-
}
|
|
1687
|
-
function encodeRandom() {
|
|
1688
|
-
let out = "";
|
|
1689
|
-
for (let i = 0; i < RANDOM_LEN; i++) out += CROCKFORD[Math.floor(Math.random() * 32)];
|
|
1690
|
-
return out;
|
|
1691
|
-
}
|
|
1692
|
-
/** A 26-char Crockford Base32 ULID (10-char time + 16-char random). */
|
|
1693
|
-
function ulid() {
|
|
1694
|
-
return encodeTime(Date.now()) + encodeRandom();
|
|
1695
|
-
}
|
|
1696
|
-
function generatePartId(prefix) {
|
|
1697
|
-
return `${prefix}_${ulid()}`;
|
|
1698
|
-
}
|
|
1699
|
-
//#endregion
|
|
1700
|
-
//#region src/document/plain-memory-adapter.ts
|
|
1701
|
-
/**
|
|
1702
|
-
* Pure in-memory `SemanticDocumentAdapter` — no Loro/WASM. Holds a
|
|
1703
|
-
* `VideoDocumentDraft` object and applies each `transact` via immer `produce`,
|
|
1704
|
-
* journaling every audit that actually mutated state (plus any ids minted
|
|
1705
|
-
* during that transact).
|
|
1706
|
-
*
|
|
1707
|
-
* Known benign difference vs `MirrorVideoDocumentAdapter`: the editor's
|
|
1708
|
-
* `setPart` assigns a fresh part object on every call, so a same-value rewrite
|
|
1709
|
-
* produces a new immer state and IS journaled here, while the mirror's deep
|
|
1710
|
-
* diff emits no commit. Terminal `snapshot()` stays equal; replay is idempotent.
|
|
1711
|
-
*/
|
|
1712
|
-
var PlainMemoryAdapter = class {
|
|
1713
|
-
state;
|
|
1714
|
-
_journal = [];
|
|
1715
|
-
baseIdFactory;
|
|
1716
|
-
/** Non-null only while a `transact` edit callback is running. */
|
|
1717
|
-
pendingIds = null;
|
|
1718
|
-
/**
|
|
1719
|
-
* Recording wrapper around the underlying factory. Callers (sandbox editor)
|
|
1720
|
-
* use this so every minted id is appended to the current transact's list.
|
|
1721
|
-
*/
|
|
1722
|
-
idFactory;
|
|
1723
|
-
constructor(document, options) {
|
|
1724
|
-
assertValidVideoDocument(document);
|
|
1725
|
-
const draft = {};
|
|
1726
|
-
writeVideoDocumentToDraft(draft, document);
|
|
1727
|
-
this.state = draft;
|
|
1728
|
-
this.baseIdFactory = options?.idFactory ?? generatePartId;
|
|
1729
|
-
this.idFactory = (prefix) => {
|
|
1730
|
-
const id = this.baseIdFactory(prefix);
|
|
1731
|
-
if (this.pendingIds != null) this.pendingIds.push(id);
|
|
1732
|
-
return id;
|
|
1733
|
-
};
|
|
1734
|
-
}
|
|
1735
|
-
get journal() {
|
|
1736
|
-
return this._journal;
|
|
1737
|
-
}
|
|
1738
|
-
hasContent() {
|
|
1739
|
-
return (this.state.meta?.schema_version ?? "") !== "";
|
|
1740
|
-
}
|
|
1741
|
-
snapshot() {
|
|
1742
|
-
return readVideoDocumentFromDraft(this.state);
|
|
1743
|
-
}
|
|
1744
|
-
/**
|
|
1745
|
-
* Apply one op via immer. A throw in `edit` discards the draft (state and
|
|
1746
|
-
* journal unchanged). When `produce` returns the same reference, there was
|
|
1747
|
-
* no structural change — skip journal, matching mirror "no change, no commit".
|
|
1748
|
-
*/
|
|
1749
|
-
transact(edit, audit) {
|
|
1750
|
-
this.pendingIds = [];
|
|
1751
|
-
try {
|
|
1752
|
-
const next = produce(this.state, edit);
|
|
1753
|
-
if (next !== this.state) {
|
|
1754
|
-
this.state = next;
|
|
1755
|
-
this._journal.push({
|
|
1756
|
-
...audit,
|
|
1757
|
-
generated_ids: this.pendingIds
|
|
1758
|
-
});
|
|
1759
|
-
}
|
|
1760
|
-
} finally {
|
|
1761
|
-
this.pendingIds = null;
|
|
1762
|
-
}
|
|
1763
|
-
}
|
|
1764
|
-
};
|
|
1765
|
-
/** Build a `PlainMemoryAdapter` seeded with `document`. */
|
|
1766
|
-
function createPlainMemoryAdapter(document, options) {
|
|
1767
|
-
return new PlainMemoryAdapter(document, options);
|
|
1768
|
-
}
|
|
1769
|
-
//#endregion
|
|
1770
|
-
export { resolveSpeechOverlapByShiftingVideos as A, partUnionToDraft as B, solveVideoDocument as C, reassignSpeechesToVideoClipsByTime as D, fillMainTrackTimeGaps as E, safeDurationMs as F, videoDocumentMirrorSchema as H, DEFAULT_UNIT_TIME_MS as I, VIDEO_DOCUMENT_SCHEMA_VERSION as L, TIMELINE_SKELETON_DURATION_MS as M, isEmptyVideoClip as N, recalculateTimelineDuration as O, partDurationMs as P, effectiveVideoClipDurationMs as R, laneTrackId as S, arrangeMainTrackSeamlessly as T, base64ToBytes as U, recordEntries as V, bytesToBase64 as W, partUnionSchema as _, createMirrorVideoDocument as a, ensureLaneTrack as b, readVideoDocumentFromDraft as c, derivePositionFromAbs as d, fromVideoDocument as f, validateVideoDocument as g, assertValidVideoDocument as h, MirrorVideoDocumentAdapter as i, syncAggregatedClipsTimePosition as j, resolveAllSpeechOverlaps as k, buildInitialVideoDocument as l, VideoDocumentValidationError as m, createPlainMemoryAdapter as n, createMirrorVideoDocumentAdapter as o, toVideoDocument as p, generatePartId as r, writeVideoDocumentToDraft as s, PlainMemoryAdapter as t, buildSpeechHostMap as u, videoDocumentSchema as v, cascadeAfterVideoClipChanges as w, findLaneTrack as x, LANE_KINDS_IN_STACK_ORDER as y, speedOf as z };
|
|
1666
|
+
export { partDurationMs as A, reassignSpeechesToVideoClipsByTime as C, syncAggregatedClipsTimePosition as D, resolveSpeechOverlapByShiftingVideos as E, partUnionToDraft as F, recordEntries as I, videoDocumentMirrorSchema as L, DEFAULT_UNIT_TIME_MS as M, VIDEO_DOCUMENT_SCHEMA_VERSION as N, TIMELINE_SKELETON_DURATION_MS as O, effectiveVideoClipDurationMs as P, base64ToBytes as R, fillMainTrackTimeGaps as S, resolveAllSpeechOverlaps as T, findLaneTrack as _, buildInitialVideoDocument as a, cascadeAfterVideoClipChanges as b, fromVideoDocument as c, assertValidVideoDocument as d, validateVideoDocument as f, ensureLaneTrack as g, LANE_KINDS_IN_STACK_ORDER as h, readVideoDocumentFromDraft as i, safeDurationMs as j, isEmptyVideoClip as k, toVideoDocument as l, videoDocumentSchema as m, createMirrorVideoDocument as n, buildSpeechHostMap as o, partUnionSchema as p, createMirrorVideoDocumentAdapter as r, derivePositionFromAbs as s, MirrorVideoDocumentAdapter as t, VideoDocumentValidationError as u, laneTrackId as v, recalculateTimelineDuration as w, arrangeMainTrackSeamlessly as x, solveVideoDocument as y, bytesToBase64 as z };
|