@mengine/medeo-client 1.2.1-alpha.4 → 1.2.1-alpha.5
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-C-h5-rCG.js → document-ClBRZtLn.js} +22 -126
- package/dist/{index-DkJ0JK2t.d.ts → index-DpD_SncO.d.ts} +628 -105
- package/dist/index.d.ts +25 -38
- package/dist/index.js +609 -151
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -40
- package/package.json +4 -7
- package/dist/index-CiDSfSMi.d.ts +0 -613
- package/dist/schemas.d.ts +0 -2
- package/dist/schemas.js +0 -541
|
@@ -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(),
|
|
@@ -838,7 +838,8 @@ const trackItemTimePositionSchema = z.discriminatedUnion("mode", [
|
|
|
838
838
|
const trackItemSchema = z.object({
|
|
839
839
|
part_id: z.string(),
|
|
840
840
|
time_position: trackItemTimePositionSchema,
|
|
841
|
-
fallback_abs_ms: finiteNumber.optional()
|
|
841
|
+
fallback_abs_ms: finiteNumber.optional(),
|
|
842
|
+
duration_override_ms: z.number().finite().positive().optional()
|
|
842
843
|
}).passthrough();
|
|
843
844
|
const trackSchema = z.object({
|
|
844
845
|
id: z.string().optional(),
|
|
@@ -1391,7 +1392,7 @@ function fromVideoDocument(document) {
|
|
|
1391
1392
|
above_main_tracks: aboveTracks.map((t) => draftTrack(t, view.absByPartId)),
|
|
1392
1393
|
below_main_tracks: belowTracks.map((t) => draftTrack(t, view.absByPartId)),
|
|
1393
1394
|
part_aggregations: view.aggregations,
|
|
1394
|
-
part_library: toReadViewPartLibrary(view.partLibrary, view.durationMs, view.derivedFillerPartIds),
|
|
1395
|
+
part_library: toReadViewPartLibrary(view.partLibrary, view.durationMs, view.derivedFillerPartIds, captionDurationOverrides(document)),
|
|
1395
1396
|
version: document.meta.version
|
|
1396
1397
|
};
|
|
1397
1398
|
}
|
|
@@ -1412,7 +1413,7 @@ function fromVideoDocument(document) {
|
|
|
1412
1413
|
* and they are not part of the document (see `fromVideoDocument`). An empty clip a
|
|
1413
1414
|
* writer placed deliberately is NOT in that set and is projected normally.
|
|
1414
1415
|
*/
|
|
1415
|
-
function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds) {
|
|
1416
|
+
function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds, captionDurationByPartId) {
|
|
1416
1417
|
const out = {};
|
|
1417
1418
|
for (const [partId, part] of Object.entries(partLibrary)) {
|
|
1418
1419
|
if (derivedFillerPartIds.has(partId)) continue;
|
|
@@ -1432,7 +1433,7 @@ function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds) {
|
|
|
1432
1433
|
const caption = clone(part.caption);
|
|
1433
1434
|
out[partId] = { caption: {
|
|
1434
1435
|
...caption,
|
|
1435
|
-
duration_ms: caption.initial_duration_ms
|
|
1436
|
+
duration_ms: captionDurationByPartId.get(partId) ?? caption.initial_duration_ms
|
|
1436
1437
|
} };
|
|
1437
1438
|
} else if (part.bgm != null) out[partId] = { bgm: {
|
|
1438
1439
|
...clone(part.bgm),
|
|
@@ -1441,6 +1442,14 @@ function toReadViewPartLibrary(partLibrary, durationMs, derivedFillerPartIds) {
|
|
|
1441
1442
|
}
|
|
1442
1443
|
return out;
|
|
1443
1444
|
}
|
|
1445
|
+
function captionDurationOverrides(document) {
|
|
1446
|
+
const result = /* @__PURE__ */ new Map();
|
|
1447
|
+
for (const track of document.tracks ?? []) {
|
|
1448
|
+
if (track.parts_kind !== "caption") continue;
|
|
1449
|
+
for (const item of track.items ?? []) if (item.duration_override_ms != null) result.set(item.part_id, item.duration_override_ms);
|
|
1450
|
+
}
|
|
1451
|
+
return result;
|
|
1452
|
+
}
|
|
1444
1453
|
/** Deep-clone a part payload, dropping the derived read-view `duration_ms`. */
|
|
1445
1454
|
function omitDurationMs(part) {
|
|
1446
1455
|
const { duration_ms: _drop, ...rest } = clone(part);
|
|
@@ -1603,6 +1612,7 @@ function rowToTrack(row) {
|
|
|
1603
1612
|
time_position: item.time_position
|
|
1604
1613
|
};
|
|
1605
1614
|
if (item.fallback_abs_ms != null) result.fallback_abs_ms = item.fallback_abs_ms;
|
|
1615
|
+
if (item.duration_override_ms != null) result.duration_override_ms = item.duration_override_ms;
|
|
1606
1616
|
return result;
|
|
1607
1617
|
})
|
|
1608
1618
|
};
|
|
@@ -1677,7 +1687,7 @@ function createMirrorVideoDocument(document, options = {}) {
|
|
|
1677
1687
|
doc,
|
|
1678
1688
|
schema: videoDocumentMirrorSchema
|
|
1679
1689
|
}).setState((draft) => {
|
|
1680
|
-
|
|
1690
|
+
seedDraft(draft, document);
|
|
1681
1691
|
}, { origin: options.origin ?? "mengine.bootstrap" });
|
|
1682
1692
|
return doc;
|
|
1683
1693
|
}
|
|
@@ -1685,8 +1695,8 @@ function createMirrorVideoDocument(document, options = {}) {
|
|
|
1685
1695
|
function createMirrorVideoDocumentAdapter(document, options) {
|
|
1686
1696
|
return new MirrorVideoDocumentAdapter(createMirrorVideoDocument(document, options));
|
|
1687
1697
|
}
|
|
1688
|
-
/** Write a whole `VideoDocument` into
|
|
1689
|
-
function
|
|
1698
|
+
/** Write a whole `VideoDocument` into the mirror draft (used to seed a fresh doc). */
|
|
1699
|
+
function seedDraft(draft, document) {
|
|
1690
1700
|
draft.meta = {
|
|
1691
1701
|
schema_version: document.meta.schema_version,
|
|
1692
1702
|
draft_id: document.meta.draft_id ?? void 0,
|
|
@@ -1711,124 +1721,10 @@ function toTrackRow(track) {
|
|
|
1711
1721
|
items: (track.items ?? []).map((item) => ({
|
|
1712
1722
|
part_id: item.part_id,
|
|
1713
1723
|
time_position: item.time_position,
|
|
1714
|
-
fallback_abs_ms: item.fallback_abs_ms
|
|
1724
|
+
fallback_abs_ms: item.fallback_abs_ms,
|
|
1725
|
+
duration_override_ms: item.duration_override_ms
|
|
1715
1726
|
}))
|
|
1716
1727
|
};
|
|
1717
1728
|
}
|
|
1718
1729
|
//#endregion
|
|
1719
|
-
|
|
1720
|
-
/**
|
|
1721
|
-
* Part-id generation, aligned with the online ecosystem.
|
|
1722
|
-
*
|
|
1723
|
-
* The authoritative online producers — agent-harness (`@harness/shared`
|
|
1724
|
-
* `genObjId`) and director.v2 (`common/obj_id.py` `gen_obj_id`) — both mint part
|
|
1725
|
-
* ids as `` `${prefix}_${ulid()}` ``, and real captured drafts use exactly that
|
|
1726
|
-
* shape (`clip_…` / `spe_…` / `cap_…` / `bgm_…`, each a 26-char ULID). The engine
|
|
1727
|
-
* previously emitted `vc_<base36 timestamp><6 random>`, a different prefix AND a
|
|
1728
|
-
* different encoding — the sole cross-repo id divergence. This module removes it
|
|
1729
|
-
* by emitting the same `<prefix>_<ULID>` bytes.
|
|
1730
|
-
*
|
|
1731
|
-
* The ULID is generated inline (Crockford Base32, 48-bit time + 80-bit random)
|
|
1732
|
-
* rather than pulling the `ulid` npm package: the randomness class matches the
|
|
1733
|
-
* old generator (both `Math.random`-based) and it keeps `@mengine/medeo-client`
|
|
1734
|
-
* dependency-free for a purely mechanical id string. Part ids only need to be
|
|
1735
|
-
* unique and lexicographically time-sortable, which this satisfies.
|
|
1736
|
-
*/
|
|
1737
|
-
/** Crockford Base32 alphabet (no I, L, O, U), per the ULID spec. */
|
|
1738
|
-
const CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
1739
|
-
const TIME_LEN = 10;
|
|
1740
|
-
const RANDOM_LEN = 16;
|
|
1741
|
-
function encodeTime(now) {
|
|
1742
|
-
let out = "";
|
|
1743
|
-
let ms = now;
|
|
1744
|
-
for (let i = TIME_LEN - 1; i >= 0; i--) {
|
|
1745
|
-
const mod = ms % 32;
|
|
1746
|
-
out = CROCKFORD[mod] + out;
|
|
1747
|
-
ms = (ms - mod) / 32;
|
|
1748
|
-
}
|
|
1749
|
-
return out;
|
|
1750
|
-
}
|
|
1751
|
-
function encodeRandom() {
|
|
1752
|
-
let out = "";
|
|
1753
|
-
for (let i = 0; i < RANDOM_LEN; i++) out += CROCKFORD[Math.floor(Math.random() * 32)];
|
|
1754
|
-
return out;
|
|
1755
|
-
}
|
|
1756
|
-
/** A 26-char Crockford Base32 ULID (10-char time + 16-char random). */
|
|
1757
|
-
function ulid() {
|
|
1758
|
-
return encodeTime(Date.now()) + encodeRandom();
|
|
1759
|
-
}
|
|
1760
|
-
function generatePartId(prefix) {
|
|
1761
|
-
return `${prefix}_${ulid()}`;
|
|
1762
|
-
}
|
|
1763
|
-
//#endregion
|
|
1764
|
-
//#region src/document/plain-memory-adapter.ts
|
|
1765
|
-
/**
|
|
1766
|
-
* Pure in-memory `SemanticDocumentAdapter` — no Loro/WASM. Holds a
|
|
1767
|
-
* `VideoDocumentDraft` object and applies each `transact` via immer `produce`,
|
|
1768
|
-
* journaling every audit that actually mutated state (plus any ids minted
|
|
1769
|
-
* during that transact).
|
|
1770
|
-
*
|
|
1771
|
-
* Known benign difference vs `MirrorVideoDocumentAdapter`: the editor's
|
|
1772
|
-
* `setPart` assigns a fresh part object on every call, so a same-value rewrite
|
|
1773
|
-
* produces a new immer state and IS journaled here, while the mirror's deep
|
|
1774
|
-
* diff emits no commit. Terminal `snapshot()` stays equal; replay is idempotent.
|
|
1775
|
-
*/
|
|
1776
|
-
var PlainMemoryAdapter = class {
|
|
1777
|
-
state;
|
|
1778
|
-
_journal = [];
|
|
1779
|
-
baseIdFactory;
|
|
1780
|
-
/** Non-null only while a `transact` edit callback is running. */
|
|
1781
|
-
pendingIds = null;
|
|
1782
|
-
/**
|
|
1783
|
-
* Recording wrapper around the underlying factory. Callers (sandbox editor)
|
|
1784
|
-
* use this so every minted id is appended to the current transact's list.
|
|
1785
|
-
*/
|
|
1786
|
-
idFactory;
|
|
1787
|
-
constructor(document, options) {
|
|
1788
|
-
assertValidVideoDocument(document);
|
|
1789
|
-
const draft = {};
|
|
1790
|
-
writeVideoDocumentToDraft(draft, document);
|
|
1791
|
-
this.state = draft;
|
|
1792
|
-
this.baseIdFactory = options?.idFactory ?? generatePartId;
|
|
1793
|
-
this.idFactory = (prefix) => {
|
|
1794
|
-
const id = this.baseIdFactory(prefix);
|
|
1795
|
-
if (this.pendingIds != null) this.pendingIds.push(id);
|
|
1796
|
-
return id;
|
|
1797
|
-
};
|
|
1798
|
-
}
|
|
1799
|
-
get journal() {
|
|
1800
|
-
return this._journal;
|
|
1801
|
-
}
|
|
1802
|
-
hasContent() {
|
|
1803
|
-
return (this.state.meta?.schema_version ?? "") !== "";
|
|
1804
|
-
}
|
|
1805
|
-
snapshot() {
|
|
1806
|
-
return readVideoDocumentFromDraft(this.state);
|
|
1807
|
-
}
|
|
1808
|
-
/**
|
|
1809
|
-
* Apply one op via immer. A throw in `edit` discards the draft (state and
|
|
1810
|
-
* journal unchanged). When `produce` returns the same reference, there was
|
|
1811
|
-
* no structural change — skip journal, matching mirror "no change, no commit".
|
|
1812
|
-
*/
|
|
1813
|
-
transact(edit, audit) {
|
|
1814
|
-
this.pendingIds = [];
|
|
1815
|
-
try {
|
|
1816
|
-
const next = produce(this.state, edit);
|
|
1817
|
-
if (next !== this.state) {
|
|
1818
|
-
this.state = next;
|
|
1819
|
-
this._journal.push({
|
|
1820
|
-
...audit,
|
|
1821
|
-
generated_ids: this.pendingIds
|
|
1822
|
-
});
|
|
1823
|
-
}
|
|
1824
|
-
} finally {
|
|
1825
|
-
this.pendingIds = null;
|
|
1826
|
-
}
|
|
1827
|
-
}
|
|
1828
|
-
};
|
|
1829
|
-
/** Build a `PlainMemoryAdapter` seeded with `document`. */
|
|
1830
|
-
function createPlainMemoryAdapter(document, options) {
|
|
1831
|
-
return new PlainMemoryAdapter(document, options);
|
|
1832
|
-
}
|
|
1833
|
-
//#endregion
|
|
1834
|
-
export { resolveAllSpeechOverlaps as A, effectiveVideoClipDurationMs as B, solveVideoDocument as C, reassignSpeechesToVideoClipsByTime as D, fillMainTrackTimeGaps as E, isEmptyVideoClip as F, base64ToBytes as G, partUnionToDraft as H, partDurationMs as I, bytesToBase64 as K, safeDurationMs as L, resolveSpeechOverlapByShiftingVideos as M, syncAggregatedClipsTimePosition as N, recalculateTimelineDuration as O, TIMELINE_SKELETON_DURATION_MS as P, DEFAULT_UNIT_TIME_MS as R, laneTrackId as S, arrangeMainTrackSeamlessly as T, recordEntries as U, speedOf as V, videoDocumentMirrorSchema 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, resolveAnchoredClipsTimePosition as j, recoverOrphanedSpeechAnchorsByTime 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, VIDEO_DOCUMENT_SCHEMA_VERSION as z };
|
|
1730
|
+
export { TIMELINE_SKELETON_DURATION_MS as A, base64ToBytes as B, reassignSpeechesToVideoClipsByTime as C, resolveAnchoredClipsTimePosition as D, resolveAllSpeechOverlaps as E, VIDEO_DOCUMENT_SCHEMA_VERSION as F, effectiveVideoClipDurationMs as I, partUnionToDraft as L, partDurationMs as M, safeDurationMs as N, resolveSpeechOverlapByShiftingVideos as O, DEFAULT_UNIT_TIME_MS as P, recordEntries as R, fillMainTrackTimeGaps as S, recoverOrphanedSpeechAnchorsByTime as T, bytesToBase64 as V, 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, isEmptyVideoClip as j, syncAggregatedClipsTimePosition 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, videoDocumentMirrorSchema as z };
|