@mengine/medeo-client 2.0.1-alpha.2 → 2.0.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.
- package/README.md +45 -110
- package/dist/document-B_JQwrC5.js +1630 -0
- package/dist/{index-B31KeDzA.d.ts → index-CnZ9l3rb.d.ts} +708 -409
- package/dist/index.d.ts +131 -737
- package/dist/index.js +971 -2728
- package/dist/{loro-relay-doc-ssdYpuef.js → loro-relay-doc-cJSY-uau.js} +7 -2
- package/dist/relay.js +1 -1
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +4 -58
- package/package.json +7 -12
- package/dist/document-BSAUud6c.js +0 -4537
- package/dist/index-CMa6ZCtX.d.ts +0 -609
- package/dist/schemas.d.ts +0 -2
- package/dist/schemas.js +0 -482
- package/dist/shared-iWnU2osE.js +0 -39
package/README.md
CHANGED
|
@@ -2,113 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
Medeo domain client for the `mengine` document path.
|
|
4
4
|
|
|
5
|
-
This package owns
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
and
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
owns clip properties such as volume; `Track` owns track properties. References
|
|
51
|
-
between entities belong in Relations, not in payload IDs. There is no separate
|
|
52
|
-
timing profile. The compatibility reader supports the existing four lanes:
|
|
53
|
-
one image/video main track, Voice, Caption, and background Audio. It accepts
|
|
54
|
-
explicit millisecond media coordinates and linear visual remapping
|
|
55
|
-
`{ kind: 'linear', rate: 2 }` (including still-image display speed). Nonlinear
|
|
56
|
-
speed and multiple visual overlay tracks are not existing editor capabilities
|
|
57
|
-
and remain outside this adapter; unsupported layouts fail before persistence.
|
|
58
|
-
Effective duration and absolute target coordinates must be whole milliseconds
|
|
59
|
-
for this reader; generic DSL coordinates are not globally restricted to that
|
|
60
|
-
unit or precision. Sequential placement stays `Clip.order` plus no targetRange,
|
|
61
|
-
so later duration edits continue to move following Clips.
|
|
62
|
-
|
|
63
|
-
Entity-authoritative editor consumers use the Loro session only to receive the
|
|
64
|
-
server-authored compatibility view. Configure that session as read-only: even
|
|
65
|
-
cold-start reconciliation must not POST legacy `/updates`. Entity writes use
|
|
66
|
-
the independent graph CAS endpoint.
|
|
67
|
-
|
|
68
|
-
Anchored placement is a `clip-anchor` Relation from child Clip to host Clip
|
|
69
|
-
plus `SequenceMarker.anchorOffset`. Voice and Caption can be independently
|
|
70
|
-
placed or explicitly anchored; generation relations do not choose a host. `resolveEntityTimelineLayout` resolves this graph
|
|
71
|
-
without reparenting or synthesizing content. Move/delete operations must write
|
|
72
|
-
their follow, keep-absolute, cascade, or detach decisions into the same entity
|
|
73
|
-
plan. A speech-overlap shift is explicit placement on the real visual Clips;
|
|
74
|
-
an uncovered time interval does not require an invented empty-media entity.
|
|
75
|
-
|
|
76
|
-
Generated Voice links to a pre-existing PhoneticScript through `phonetic-script-render`.
|
|
77
|
-
Caption and PhoneticScript each compose a real AudioScript by directly holding `baseEntityIds`, an array that may compose multiple entities. AudioScript owns
|
|
78
|
-
`segments[].text`; assembly never automatically persists a copy on the variants. Read complete content
|
|
79
|
-
with `assembleCaptionContent` or `assemblePhoneticScriptContent`. Broken composition
|
|
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
|
-
`audio-script-source`, without creating a synthesis variant.
|
|
82
|
-
|
|
83
|
-
`insertCaptionClip` requires `baseEntityIds` and one `selection` object; its optional `captionEntityId` preserves a generation-provided business identity independently of `captionClipEntityId`. The selection
|
|
84
|
-
names a source `segmentId` and optionally a half-open Unicode code-point
|
|
85
|
-
`textRange: {start, end}`. This permits display re-segmentation without rewriting
|
|
86
|
-
the original script. `upsertVoiceoverTake` requires the real
|
|
87
|
-
`phoneticScriptEntityId` used for synthesis; its captions supply their own `baseEntityIds` and select the same script.
|
|
88
|
-
External speech identity and storage key stay on Voice.
|
|
89
|
-
|
|
90
|
-
AudioScript has no intrinsic Sequence and cannot enter a Clip. `audio-script-marker`
|
|
91
|
-
attaches directly assigned `segmentRanges` timing; annotation Markers never refer
|
|
92
|
-
to upstream Markers and cannot be Clip display Markers. Moving or aligning a
|
|
93
|
-
Caption changes its external display Marker, preserving intrinsic Caption extent.
|
|
94
|
-
Caption owns its styles and text selection. Background Audio's Marker declares
|
|
95
|
-
`durationPolicy: 'timeline'`: its source duration stays factual,
|
|
96
|
-
while the view fills the non-BGM timeline duration.
|
|
97
|
-
|
|
98
|
-
`migrateLegacyTimelineToEntities` is a one-time migration utility, **not** an
|
|
99
|
-
ordinary editing diff adapter. A configured legacy document requires a separate
|
|
100
|
-
CAS commit with `migrationBaseVv` equal to its current canonical base64 Loro
|
|
101
|
-
oplog version. The server calls `assertEntityProjectionPreservesLegacy` to reject
|
|
102
|
-
stale or lossy migrations. Only then can a new edit be committed.
|
|
103
|
-
|
|
104
|
-
The legacy `SemanticEditor` remains available for pre-cutover library consumers.
|
|
105
|
-
It rejects `video-document/entity-projection-v1` documents. Production entity
|
|
106
|
-
tools and editor adapters must not fall back to it or raw `/updates` on failure.
|
|
107
|
-
For an entity projection, `meta.version` is the committed entity revision; the
|
|
108
|
-
Loro version vector remains the transport-sync cursor.
|
|
109
|
-
|
|
110
|
-
### Transparent variant fields in the DSL sandbox
|
|
111
|
-
|
|
112
|
-
`entities.get/list` return complete assembled fields. Consumers do not query base IDs or merge source payloads. `entities.update` patches supplied fields, preserves omitted fields, and routes inherited fields to their declaring entity. Explicit own-field declarations use `entities.declareFields`; these override unambiguous base fields without changing the base. Persisted entity rows and command payloads contain owned fields only. Base collisions are validated before own overrides.
|
|
113
|
-
|
|
114
|
-
`prepareCaptionContent` accepts caption authoring intent and handles source composition, visible text selection, and preservation of existing intrinsic timing inside the SDK.
|
|
5
|
+
This package owns the shared `VideoDocument` contract, semantic editing layer, and runtime-neutral HTTP/SSE client used by medeo-web, agent-harness, and server-side validation code. UI adapters such as `DraftMutationDriver` stay in product repositories.
|
|
6
|
+
|
|
7
|
+
`MengineDocSession.start()` waits for DocManager to load a local snapshot, or for the first remote sync if no local snapshot exists, then validates the content. A cached document can open before SSE connects; a cold start waits for SSE and the existing sync cycle. Session does not prefetch or import an initial snapshot itself.
|
|
8
|
+
|
|
9
|
+
`getState().loaded` means the first local load completed. Once loaded, `loadedFromLocal` reports whether that load imported a snapshot, including a valid empty document. It stays unchanged by later edits and remote updates. Document readiness does not depend on metadata or nonempty tracks.
|
|
10
|
+
|
|
11
|
+
## Local persistence
|
|
12
|
+
|
|
13
|
+
Browser hosts can inject `IndexedDBDocStorage` through `localStorage`. An optional `initialSnapshot` merges a freshly fetched server snapshot into that storage before DocManager loads it; it never replaces locally saved, unconfirmed edits. The host can require a successful online fetch before constructing the session.
|
|
14
|
+
|
|
15
|
+
`getLocalSaveState()` / `subscribeLocalSaveState()` report `{ status: 'saving' | 'saved' | 'failed', error }` for this session's local commits. This is separate from `getSyncState()` and server confirmation. The storage adapter determines durability: IndexedDB resolves only after its transaction commits; MemoryDocStorage remains in memory. Failed saves retain their causal order and retry without blocking other documents.
|
|
16
|
+
|
|
17
|
+
`waitForLocalSave({ timeoutMs? })` waits for the commits present at invocation (default deadline: 15 seconds). Later edits do not extend that target. Timing out only stops the wait; persistence continues. This does not wait for server acknowledgement.
|
|
18
|
+
|
|
19
|
+
For normal teardown, use `await session.close()`. It immediately rejects new edits and stops synchronization, then keeps local persistence alive until pending commits are saved before releasing connections. Storage failures remain retryable while closing. `destroy()` is immediate cancellation for exceptional teardown, including failed startup; it can discard unpersisted in-memory work. Neither API can guarantee a save after the browser process is forcibly terminated. Only completed local saves survive reopening.
|
|
20
|
+
|
|
21
|
+
Edits received from another local-storage peer also remain unconfirmed until covered by an authoritative server version. Receiving a cross-tab notification is not a server acknowledgement.
|
|
22
|
+
|
|
23
|
+
Reopening uses the stored Loro history and the server's version vector to derive missing updates, without replaying semantic operations or their external side effects. Undo history remains limited to the current session.
|
|
24
|
+
|
|
25
|
+
## Session undo/redo
|
|
26
|
+
|
|
27
|
+
After `await session.start()`, `session.undo(options?)` and `session.redo(options?)` synchronously apply local history and return whether they produced a document update. `options` accepts the same actor/intent metadata as semantic edits. Read the resulting document through `session.snapshot()`; use `waitForServerAck()` only when durable confirmation is required.
|
|
28
|
+
|
|
29
|
+
`getUndoState()` returns the current `{ canUndo, canRedo }` immediately. `subscribeUndoState(callback)` immediately provides that state, then coalesces subsequent stack changes in a microtask after mutations settle. Several synchronous commands may produce only one availability notification; use the getter when reading directly after a command. Teardown publishes empty availability synchronously and cancels pending notifications. Dispose the returned subscription with the host. Loading and closed sessions report an empty history; history commands require a ready session.
|
|
30
|
+
|
|
31
|
+
History belongs to one document/session peer. The loaded baseline and remote imports are not recorded. Each semantic commit is a separate step (up to 100); a new local edit invalidates redo. Reconnecting preserves history, while reopening starts empty. Empty or ineffective history actions return false. Never reuse a peer ID across concurrent sessions.
|
|
32
|
+
|
|
33
|
+
Use `beginUndoGroup()` / `endUndoGroup()` to combine existing semantic operations into one undo step, or to combine repeated commits during one gesture. Always end in `finally`. Every constituent commit is immediately visible locally and enters synchronization independently; if a later operation fails, earlier commits remain applied. Conflicting remote imports may split/end a group early, and unrelated local edits in the same session would join an open group.
|
|
34
|
+
|
|
35
|
+
Mirror's draft callback and commit are synchronous. SemanticEditor methods return promises, but their document mutations currently finish synchronously before the promise resolves. Await external asset generation before opening a group, then compose the local semantic operations. Keeping a group open across asynchronous work does not provide transaction isolation, deferred publication, or rollback. If several changes must be atomic, implement one semantic operation with one synchronous draft callback. A gesture that uses only local previews and commits once on release already needs no group.
|
|
36
|
+
|
|
37
|
+
Flush pending local preview/debounce work before undo/redo. Mutating again from a document-update observer during a mutation is rejected; schedule the next command after the current one returns.
|
|
38
|
+
|
|
39
|
+
The session assembles SemanticEditor with MirrorVideoDocumentAdapter directly. DocumentUndoManager independently observes the same LoroDoc and owns undo/redo, grouping and audit metadata. Both write paths share a synchronous DocumentMutationGuard; the session closes it before teardown callbacks, and each component releases its own resources. Standalone adapters create their own guard by default and reject use after disposal while leaving the borrowed LoroDoc usable.
|
|
40
|
+
|
|
41
|
+
Undo/redo append ordinary synchronized updates and retain audit metadata (`Undo`/`Redo`, actor, and `payload.source` identifying an original local change). Existing revision bindings remain immutable. Redo reuses already materialized assets without repeating generation, billing, or attachment requests. Network failures do not automatically reverse history.
|
|
42
|
+
|
|
43
|
+
Loro history uses new writes: undo on a shared LWW field restores its value before the local edit, potentially overwriting a later remote write to the same field; redo restores the value visible before undo. Unrelated remote fields remain intact. Undoing a local insertion removes the object and makes dependent remote edits invisible until redo restores the object. Caption creation includes its style container, even when empty, so a later style edit only changes fields and undo preserves another peer's independently edited fields. Initial document seeding preserves supplied styles and creates empty maps for captions without styles. No write-time repair or migration of older CRDT documents is provided.
|
|
44
|
+
|
|
45
|
+
## Large-update resynchronization
|
|
46
|
+
|
|
47
|
+
`MengineDocSession` handles SSE `event: resync` by scheduling the existing version-vector sync on the current connection. The event carries no Loro bytes and does not create an edit or undo step. A hint arriving while an HTTP sync is in flight schedules another diff so changes newer than that response are still fetched. Low-level users of `readMengineEventStream` can handle the same hint with `onResync`; `MedeoHttpDocStorage` exposes `subscribeResync`.
|
|
48
|
+
|
|
49
|
+
Deploy this client before enabling server-side resync notifications. Older clients ignore the event. Large HTTP pushes remain valid: the server chooses inline update or resync notification after persistence, rather than requiring client-side fragmentation. Base64 encoding uses `Uint8Array.toBase64()` where available, with a chunked fallback preserving the same padded wire representation.
|