@mengine/medeo-client 2.1.1-dsl.22 → 2.1.1-dsl.24
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 +10 -6
- package/dist/{dsl-B7-4dMjr.js → dsl-Bvv_51Ns.js} +175 -38
- package/dist/dsl.d.ts +2 -2
- package/dist/dsl.js +2 -2
- package/dist/{index-CcNkkQll.d.ts → index-BGEcTwoD.d.ts} +5 -3
- package/dist/{index-D4Bgukns.d.ts → index-BOgr8p8C.d.ts} +7 -4
- package/dist/{index-DVmvFhEn.d.ts → index-CmuDB_Gm.d.ts} +9 -13
- package/dist/index.d.ts +4 -4
- package/dist/index.js +28 -6
- package/dist/legacy.d.ts +2 -2
- package/dist/legacy.js +2 -2
- package/dist/{storage-BW3tI_ER.js → storage-evqvKS4B.js} +5 -1
- package/dist/testing.d.ts +4 -2
- package/dist/testing.js +45 -26
- package/dist/{video-draft-types-BfIXM8q3.js → video-draft-types-DRGBN0we.js} +44 -12
- package/dist/{video-draft-types-0J2vfXBu.d.ts → video-draft-types-slnHaNs9.d.ts} +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -16,16 +16,14 @@ const [clipId] = session.editor.addClips({
|
|
|
16
16
|
session.editor.setClipVolume(clipId, -3, { actor: { user_id: userId, role: 'user' } });
|
|
17
17
|
await session.waitForServerAck(); // Local completion is separate from durable confirmation.
|
|
18
18
|
const { content, diagnostics } = session.projectVideoDraft();
|
|
19
|
-
session.
|
|
19
|
+
await session.close();
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
`start()`, `snapshot()` and subscription events expose `MedeoDslSnapshot`. `session.dsl` exposes controlled `transact`/`applyMutations`; ordinary business callers use `session.editor`. Rich text uses the native text adapter. `readonlyMode` blocks editing and Undo/Redo. Closing a session also invalidates captured editor/document references.
|
|
23
23
|
|
|
24
|
-
For explicit synchronization, use `ManualSyncDoc.open({client, peerId})`, then `pull()`, `editor`, `push()` and `dispose()`. Both lifecycles use the same binary snapshot/update and version-coverage contracts. Neither silently upgrades old documents or overwrites an incompatible cache.
|
|
25
|
-
|
|
26
24
|
## Local persistence
|
|
27
25
|
|
|
28
|
-
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.
|
|
26
|
+
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 incoming snapshot and combined local history are format-checked before the merge is persisted. The host can require a successful online fetch before constructing the session.
|
|
29
27
|
|
|
30
28
|
`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.
|
|
31
29
|
|
|
@@ -37,6 +35,8 @@ Edits received from another local-storage peer also remain unconfirmed until cov
|
|
|
37
35
|
|
|
38
36
|
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.
|
|
39
37
|
|
|
38
|
+
For explicit synchronization, use `ManualSyncDoc.open({client, peerId})`, then `pull()`, `editor`, `push()` and `dispose()`. Both lifecycles use the same binary snapshot/update and version-coverage contracts. Neither silently upgrades old documents or overwrites an incompatible cache.
|
|
39
|
+
|
|
40
40
|
## Editing and conversion
|
|
41
41
|
|
|
42
42
|
- Track: create, reorder, hide and delete.
|
|
@@ -126,7 +126,7 @@ Each handle owns one long-lived Mirror. Ordinary fields and Tree read from its i
|
|
|
126
126
|
|
|
127
127
|
Mirror 2.3.3 cannot safely move an existing node under a parent created in the same draft. The document transaction rejects this combination before writing. When a business Action actually needs it, implement its scoped native path with one audited commit as specified by [K03](../../docs/projects/medeo-dsl/known-unfixed.md#k03-mirror-同批新建父节点并移入已有节点); that fallback is not implemented yet.
|
|
128
128
|
|
|
129
|
-
Loro 1.16.1 and loro-mirror 2.3.3 are the lockfile baseline. Mirror is pinned with a [workspace dependency patch](../../patches/README.md): its optional `setState(..., {applyNative})` hook runs after the ordinary draft reaches Loro and before one commit. The full native event updates Mirror before DSL subscribers are notified. The hook is internal to the DSL adapter; Actions never receive a native-write callback. It supports non-ephemeral Mirror instances, and must not commit/export/import or await. A registry install of loro-mirror never carries the patch, so the published package bundles the patched Mirror, runtime and declarations; consumers install only the `loro-crdt` peer and configure no patch. Transactions probe the Mirror once and refuse to write when the hook is missing rather than drop native edits. Native writes preserve marks and actual container identities; a plain Mirror string snapshot still does not contain rich-text marks. Tests cover snapshot/update round trips, concurrent moves and replacements, field merging, optional reset, malformed codecs, deletion/recreation, rich text, Cursor ownership, subscriptions and Action failure preflight. The
|
|
129
|
+
Loro 1.16.1 and loro-mirror 2.3.3 are the lockfile baseline. Mirror is pinned with a [workspace dependency patch](../../patches/README.md): its optional `setState(..., {applyNative})` hook runs after the ordinary draft reaches Loro and before one commit. The full native event updates Mirror before DSL subscribers are notified. The hook is internal to the DSL adapter; Actions never receive a native-write callback. It supports non-ephemeral Mirror instances, and must not commit/export/import or await. A registry install of loro-mirror never carries the patch, so the published package bundles the patched Mirror, runtime and declarations; consumers install only the `loro-crdt` peer and configure no patch. Transactions probe the Mirror once and refuse to write when the hook is missing rather than drop native edits. Native writes preserve marks and actual container identities; a plain Mirror string snapshot still does not contain rich-text marks. Tests cover snapshot/update round trips, concurrent moves and replacements, field merging, optional reset, malformed codecs, deletion/recreation, rich text, Cursor ownership, subscriptions and Action failure preflight. The server and current tool/sandbox source entrypoints use DSL documents. Deployment and each external consumer's acceptance are tracked separately in the status document.
|
|
130
130
|
|
|
131
131
|
Run the package test/build tasks through `vp run @mengine/medeo-client#test` and `vp run @mengine/medeo-client#build`.
|
|
132
132
|
|
|
@@ -158,8 +158,12 @@ Caption text is matched forward in `speech.caption_ids` order. A failed exact ma
|
|
|
158
158
|
|
|
159
159
|
## Legacy consumers
|
|
160
160
|
|
|
161
|
-
`SemanticEditor`, `VideoDocument`, their adapters and old timeline projection have been removed. `@mengine/medeo-client/legacy` retains only the old EntityTimelineEditor, entity transport and its direct VideoDraft projection.
|
|
161
|
+
`SemanticEditor`, `VideoDocument`, their adapters and old timeline projection have been removed. `@mengine/medeo-client/legacy` retains only the old EntityTimelineEditor, entity transport and its direct VideoDraft projection. Current medeo-tool/sandbox uses the DSL entrypoints; the legacy entry supports explicitly retained Entity consumers. The obsolete timeline-journal replay rejects nonempty plans before writing. They cannot open new DSL documents. `/schemas` retains the legacy Entity tool schema contract. The current Editor uses the DSL model.
|
|
162
162
|
|
|
163
163
|
`/relay` and `/testing` remain host/test-only entrypoints. The private DSL package is bundled into the client distribution.
|
|
164
164
|
|
|
165
165
|
See [DSL index](../../docs/projects/medeo-dsl/README.md), [capability mapping and cutover](../../docs/projects/medeo-dsl/rfc/03-editor-and-document-cutover.md) and [known limits](../../docs/projects/medeo-dsl/known-unfixed.md). K04 audit segmentation is unchanged; one native commit can contain multiple Changes.
|
|
166
|
+
|
|
167
|
+
### PhoneticScript storage cutover
|
|
168
|
+
|
|
169
|
+
The row-owned atomic binding stores the selection, pronunciation and file facts together. Public Action methods and domain snapshots retain their shape; the native Loro field layout requires matching SDK/server versions. Old field-per-fact DSL documents require explicit migration and are refused by the new reader and relay. See [the cutover contract](../../docs/projects/medeo-dsl/rfc/06-phonetic-binding-cutover.md).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as assertCaptionContent, A as deepEqual, B as isStateAndSchemaOfType, C as validateSchema, D as cidsEqual, E as applySchemaToInferOptions, F as inferContainerTypeFromValue, G as stripUndefined, H as isValueOfContainerType, I as insertChildToMap, J as valuesEqual, K as tryInferContainerType, L as isArrayLike, M as getRootContainerByType, N as hardenCidDescriptors, O as containerIdToContainerType, P as hasTransform, Q as getMapFieldSchema, R as isObject, S as schemaContainsIgnoreField, T as applyEncode, U as safeStringify, V as isTreeID, W as schemaToContainerType, X as getChildContainerSchema, Y as CID_KEY, Z as getChildSchema, _ as isLoroListSchema, _t as assertRelationIdentity, a as assertPhoneticBindingFormat, at as assertPhoneticScript, b as isLoroTreeSchema, bt as relationId, c as captionContentCodec, ct as assertSeqMarker, d as phoneticBindingCodec, dt as entityTables, et as assertEntity, ft as isRecord, g as isListLikeSchema, gt as validLanguage, h as isContainerSchema, ht as relationTables, it as assertPhonemeScript, j as defineCidProperty, k as decodeNestedJsonValues, l as isInvalidAtomic, lt as assertTimeAnchor, m as getDefaultValue, mt as patchRow, n as textStyles, nt as assertId, ot as assertRelation, p as schema, pt as mergeFields, q as tryUpdateToContainer, rt as assertPhoneme, s as medeoDslLoroShape, st as assertScriptSegment, t as DEFAULT_UNIT_TIME_MS, tt as assertEntityPatch, u as phonemeCodec, ut as atomicFields, v as isLoroMapSchema, vt as assertResourceIdentity, w as applyDecode, x as isRootSchemaType, xt as resourceId, y as isLoroMovableListSchema, yt as defaultIdFactory, z as isObjectLike } from "./video-draft-types-DRGBN0we.js";
|
|
2
2
|
import { Cursor, LoroDoc, LoroList, LoroMap, LoroMovableList, LoroText, LoroTree, isContainer, isContainerId } from "loro-crdt";
|
|
3
3
|
import { Immer, setAutoFreeze } from "immer";
|
|
4
4
|
//#region ../medeo-dsl/src/text.ts
|
|
@@ -311,6 +311,63 @@ function assertContainTree(rows, tree) {
|
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
//#endregion
|
|
314
|
+
//#region ../medeo-dsl/src/clip-playback.ts
|
|
315
|
+
const playable = {
|
|
316
|
+
video_clip: ["video", "image"],
|
|
317
|
+
speech: ["audio", "voiceover-recording"],
|
|
318
|
+
caption: ["caption"],
|
|
319
|
+
bgm: ["audio"]
|
|
320
|
+
};
|
|
321
|
+
function supportsClipSpeed(source) {
|
|
322
|
+
return isRecord(source) && [
|
|
323
|
+
"video",
|
|
324
|
+
"audio",
|
|
325
|
+
"voiceover-recording"
|
|
326
|
+
].includes(String(source.kind));
|
|
327
|
+
}
|
|
328
|
+
/** Content-kind admission is shared by Actions, script compilation and the final transaction. */
|
|
329
|
+
function assertClipSourceRole(role, kind) {
|
|
330
|
+
if (!playable[role]?.includes(kind)) throw new Error(`A ${role} Track does not play ${kind}`);
|
|
331
|
+
}
|
|
332
|
+
function assertClipWindow(window, duration) {
|
|
333
|
+
if (!Number.isSafeInteger(window.inMs) || !Number.isSafeInteger(window.outMs) || window.inMs < 0 || window.outMs <= window.inMs) throw new Error("Invalid Clip window");
|
|
334
|
+
if (duration !== void 0 && window.outMs > duration) throw new Error(`Invalid Clip window: ${window.outMs}ms is past its content's ${duration}ms`);
|
|
335
|
+
}
|
|
336
|
+
/** Check authored playback facts; a remote merge is still read by projection with diagnostics. */
|
|
337
|
+
function assertClipPlayback(clip, source, role) {
|
|
338
|
+
if (!isRecord(source)) throw new Error("Invalid Clip source");
|
|
339
|
+
const kind = source.kind ?? "caption";
|
|
340
|
+
const marker = clip.seqMarker;
|
|
341
|
+
assertSeqMarker(marker);
|
|
342
|
+
if (marker.outMs <= marker.inMs) throw new Error("Clip window must be nonempty");
|
|
343
|
+
if (role !== void 0) assertClipSourceRole(role, kind);
|
|
344
|
+
if (marker.rate !== void 0 && !supportsClipSpeed(source)) throw new Error("Only video and sound change speed");
|
|
345
|
+
const duration = typeof source.durationMs === "number" ? source.durationMs : void 0;
|
|
346
|
+
if (marker.fillTimeline) {
|
|
347
|
+
if (kind !== "audio") throw new Error("Only BGM audio fills the Timeline");
|
|
348
|
+
if (marker.inMs !== 0 || marker.rate !== void 0 && marker.rate !== 1 || marker.outMs !== duration) throw new Error(`A Clip that fills the Timeline plays its whole source at 1×: inMs 0, outMs ${duration ?? "its length"}, no rate; the Timeline's end cuts it`);
|
|
349
|
+
}
|
|
350
|
+
assertClipWindow(marker);
|
|
351
|
+
}
|
|
352
|
+
function clipParents(tree) {
|
|
353
|
+
const result = /* @__PURE__ */ new Map();
|
|
354
|
+
for (const track of tree) for (const clip of track.children ?? []) result.set(clip.entityId, track.entityId);
|
|
355
|
+
return result;
|
|
356
|
+
}
|
|
357
|
+
/** A new parent or Track role revalidates that binding, without blocking unrelated merged rows. */
|
|
358
|
+
function assertClipPlacements(before, after, previousTree, nextTree) {
|
|
359
|
+
const previous = clipParents(previousTree);
|
|
360
|
+
for (const [id, parent] of clipParents(nextTree)) {
|
|
361
|
+
const track = after["track-entities"][parent];
|
|
362
|
+
const previousTrack = before["track-entities"][parent];
|
|
363
|
+
if (previous.get(id) === parent && (track === void 0 || isRecord(track) && isRecord(previousTrack) && previousTrack.role === track.role)) continue;
|
|
364
|
+
const role = requireEntity(after, "track-entities", parent).role;
|
|
365
|
+
const clip = after["clip-entities"][id];
|
|
366
|
+
if (!clip) continue;
|
|
367
|
+
assertClipPlayback(clip, after["media-entities"][clip.source] ?? after["caption-entities"][clip.source], role);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
//#endregion
|
|
314
371
|
//#region ../medeo-dsl/src/plan.ts
|
|
315
372
|
/** Include removed nested keys: a partial merge alone would conceal a deleted required field. */
|
|
316
373
|
function replacementPatch(before, after) {
|
|
@@ -326,6 +383,7 @@ function replacementPatch(before, after) {
|
|
|
326
383
|
*/
|
|
327
384
|
function assertChangeAdmitted(change) {
|
|
328
385
|
const { before, after } = change;
|
|
386
|
+
const parents = change.containment ? clipParents(change.containment.after) : void 0;
|
|
329
387
|
for (const [table, rows] of change.entities) for (const [id, fields] of rows) {
|
|
330
388
|
const value = after[table][id];
|
|
331
389
|
if (value === void 0) continue;
|
|
@@ -340,25 +398,17 @@ function assertChangeAdmitted(change) {
|
|
|
340
398
|
}
|
|
341
399
|
const row = value;
|
|
342
400
|
for (const field of referenceFields[table] ?? []) if (!old || fields.has(field)) assertReferenceAdmitted(after, table, id, field, row[field]);
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
401
|
+
if (table === "clip-entities" && (!old || fields.has("seqMarker") || fields.has("source"))) {
|
|
402
|
+
const parent = parents?.get(id);
|
|
403
|
+
assertClipPlayback(row, after["media-entities"][row.source] ?? after["caption-entities"][row.source], parent === void 0 ? void 0 : requireEntity(after, "track-entities", parent).role);
|
|
404
|
+
}
|
|
346
405
|
}
|
|
347
406
|
if (change.entities.has("timeline-entities") && Object.keys(after["timeline-entities"]).length > 1) throw new Error("Document already has a Timeline");
|
|
348
407
|
for (const [table, ids] of change.relations) for (const id of ids) {
|
|
349
408
|
const value = after[table][id];
|
|
350
409
|
if (value !== void 0) assertRelationAdmitted(after, table, id, value);
|
|
351
410
|
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* A Clip that fills the Timeline plays its whole source at 1×: the player loops a short source and
|
|
355
|
-
* cuts a long one at the Timeline's end (RFC 02 §3.3), so a window or speed of its own has no meaning.
|
|
356
|
-
*/
|
|
357
|
-
function assertFillsWithWholeSource(rows, marker, source) {
|
|
358
|
-
if (marker?.fillTimeline !== true) return;
|
|
359
|
-
const media = typeof source === "string" ? rows["media-entities"][source] : void 0;
|
|
360
|
-
const durationMs = typeof media?.durationMs === "number" ? media.durationMs : void 0;
|
|
361
|
-
if (marker.inMs !== 0 || marker.rate !== void 0 && marker.rate !== 1 || durationMs !== void 0 && marker.outMs !== durationMs) throw new Error(`A Clip that fills the Timeline plays its whole source at 1×: inMs 0, outMs ${durationMs ?? "its length"}, no rate; the Timeline's end cuts it`);
|
|
411
|
+
if (change.containment) assertClipPlacements(before, after, change.containment.before, change.containment.after);
|
|
362
412
|
}
|
|
363
413
|
//#endregion
|
|
364
414
|
//#region src/dsl/projection/types.ts
|
|
@@ -594,15 +644,11 @@ function requireSource(s, id, role) {
|
|
|
594
644
|
return media;
|
|
595
645
|
}
|
|
596
646
|
function assertMediaRole(media, role) {
|
|
597
|
-
if (!media
|
|
598
|
-
|
|
599
|
-
speech: ["audio", "voiceover-recording"],
|
|
600
|
-
bgm: ["audio"],
|
|
601
|
-
caption: []
|
|
602
|
-
}[role].includes(media.kind)) throw new Error(`Source is not allowed on ${role} Track`);
|
|
647
|
+
if (!media) throw new Error(`Missing source for ${role} Track`);
|
|
648
|
+
assertClipSourceRole(role, media.kind);
|
|
603
649
|
}
|
|
604
650
|
function validateWindow(window, duration) {
|
|
605
|
-
|
|
651
|
+
assertClipWindow(window, duration);
|
|
606
652
|
}
|
|
607
653
|
function trackOf(s, id) {
|
|
608
654
|
requireClip(s, id);
|
|
@@ -890,7 +936,8 @@ function replaceSourcePlan(s, clipId, input) {
|
|
|
890
936
|
patch: {
|
|
891
937
|
seqMarker: {
|
|
892
938
|
inMs: input.inMs,
|
|
893
|
-
outMs: input.outMs
|
|
939
|
+
outMs: input.outMs,
|
|
940
|
+
...supportsClipSpeed(source.source) ? {} : { rate: void 0 }
|
|
894
941
|
},
|
|
895
942
|
source: source.id
|
|
896
943
|
}
|
|
@@ -3905,6 +3952,54 @@ function mergeInitialIntoBaseWithSchema(base, init, rootSchema) {
|
|
|
3905
3952
|
}
|
|
3906
3953
|
}
|
|
3907
3954
|
//#endregion
|
|
3955
|
+
//#region src/dsl/document/phonetic-binding.ts
|
|
3956
|
+
/**
|
|
3957
|
+
* Actions and the transaction guard keep their domain-shaped rows. The native schema stores
|
|
3958
|
+
* a PhoneticScript's facts under one binding; this lens applies draft edits to that single value.
|
|
3959
|
+
* It never reads the retired field-per-fact representation.
|
|
3960
|
+
*/
|
|
3961
|
+
function logicalDslState(native) {
|
|
3962
|
+
const phonetics = new Proxy({}, {
|
|
3963
|
+
get: (_target, key) => typeof key === "string" ? native["phonetic-script-entities"]?.[key]?.binding : void 0,
|
|
3964
|
+
set: (_target, key, value) => {
|
|
3965
|
+
if (typeof key !== "string") throw new Error("Invalid PhoneticScript key");
|
|
3966
|
+
native["phonetic-script-entities"] ??= {};
|
|
3967
|
+
const existing = native["phonetic-script-entities"][key];
|
|
3968
|
+
if (existing) existing.binding = value;
|
|
3969
|
+
else native["phonetic-script-entities"][key] = { binding: value };
|
|
3970
|
+
return true;
|
|
3971
|
+
},
|
|
3972
|
+
deleteProperty: (_target, key) => {
|
|
3973
|
+
if (typeof key === "string") delete native["phonetic-script-entities"][key];
|
|
3974
|
+
return true;
|
|
3975
|
+
},
|
|
3976
|
+
ownKeys: () => Object.keys(native["phonetic-script-entities"] ?? {}),
|
|
3977
|
+
has: (_target, key) => typeof key === "string" && Object.hasOwn(native["phonetic-script-entities"] ?? {}, key),
|
|
3978
|
+
getOwnPropertyDescriptor: (_target, key) => typeof key === "string" && Object.hasOwn(native["phonetic-script-entities"] ?? {}, key) ? {
|
|
3979
|
+
configurable: true,
|
|
3980
|
+
enumerable: true,
|
|
3981
|
+
writable: true,
|
|
3982
|
+
value: native["phonetic-script-entities"][key].binding
|
|
3983
|
+
} : void 0
|
|
3984
|
+
});
|
|
3985
|
+
const view = {};
|
|
3986
|
+
for (const key of new Set([
|
|
3987
|
+
...Object.keys(native),
|
|
3988
|
+
...entityTables,
|
|
3989
|
+
...relationTables,
|
|
3990
|
+
"contain-relations"
|
|
3991
|
+
])) Object.defineProperty(view, key, {
|
|
3992
|
+
configurable: true,
|
|
3993
|
+
enumerable: true,
|
|
3994
|
+
get: () => key === "phonetic-script-entities" ? phonetics : Reflect.get(native, key),
|
|
3995
|
+
set: (value) => {
|
|
3996
|
+
if (key === "phonetic-script-entities") throw new Error("Cannot replace the PhoneticScript table");
|
|
3997
|
+
Reflect.set(native, key, value);
|
|
3998
|
+
}
|
|
3999
|
+
});
|
|
4000
|
+
return view;
|
|
4001
|
+
}
|
|
4002
|
+
//#endregion
|
|
3908
4003
|
//#region src/dsl/document/read.ts
|
|
3909
4004
|
/** Looking up a missing root must not create it. */
|
|
3910
4005
|
function rootMap(doc, name) {
|
|
@@ -3988,6 +4083,7 @@ function referenceTargets(table, row) {
|
|
|
3988
4083
|
}
|
|
3989
4084
|
}
|
|
3990
4085
|
function readMedeoDsl(doc, state) {
|
|
4086
|
+
const logical = logicalDslState(state);
|
|
3991
4087
|
const diagnostics = [];
|
|
3992
4088
|
const diagnostic = (code, path, error) => diagnostics.push({
|
|
3993
4089
|
code,
|
|
@@ -3997,7 +4093,7 @@ function readMedeoDsl(doc, state) {
|
|
|
3997
4093
|
const entities = Object.fromEntries(entityTables.map((t) => [t, {}]));
|
|
3998
4094
|
const relations = Object.fromEntries(relationTables.map((t) => [t, {}]));
|
|
3999
4095
|
const richText = {};
|
|
4000
|
-
for (const table of entityTables) for (const [id, raw] of Object.entries(
|
|
4096
|
+
for (const table of entityTables) for (const [id, raw] of Object.entries(logical[table] ?? {})) try {
|
|
4001
4097
|
assertId(id);
|
|
4002
4098
|
let v = raw;
|
|
4003
4099
|
for (const field of optionalReferences[table] ?? []) {
|
|
@@ -4503,7 +4599,11 @@ function validateDraft(tracked) {
|
|
|
4503
4599
|
before,
|
|
4504
4600
|
after: state,
|
|
4505
4601
|
entities: tracked.entities,
|
|
4506
|
-
relations: tracked.relations
|
|
4602
|
+
relations: tracked.relations,
|
|
4603
|
+
containment: {
|
|
4604
|
+
before: plainTree(before["contain-relations"] ?? []),
|
|
4605
|
+
after: plainTree(state["contain-relations"] ?? [])
|
|
4606
|
+
}
|
|
4507
4607
|
});
|
|
4508
4608
|
if (!tracked.treeChanged) return;
|
|
4509
4609
|
const oldNodes = nodeIndex(before["contain-relations"] ?? []);
|
|
@@ -4580,8 +4680,11 @@ function runTransaction(doc, mirror, edit, options, setReject) {
|
|
|
4580
4680
|
const steps = [];
|
|
4581
4681
|
const newCaptionTexts = /* @__PURE__ */ new Map();
|
|
4582
4682
|
const bodies = /* @__PURE__ */ new Map();
|
|
4583
|
-
const
|
|
4584
|
-
|
|
4683
|
+
const nativeBefore = mirror.getState();
|
|
4684
|
+
const before = logicalDslState(nativeBefore);
|
|
4685
|
+
const phoneticRows = /* @__PURE__ */ new Map();
|
|
4686
|
+
mirror.setState((native) => {
|
|
4687
|
+
const raw = logicalDslState(native);
|
|
4585
4688
|
const tracked = new TransactionDraft(raw, before);
|
|
4586
4689
|
setReject((error) => tracked.fail(error));
|
|
4587
4690
|
/** The current text of a Caption's own Text or a script segment, as this transaction leaves it so far. */
|
|
@@ -4773,6 +4876,15 @@ function runTransaction(doc, mirror, edit, options, setReject) {
|
|
|
4773
4876
|
for (const step of steps) if (step.type === "text") if ("captionId" in step.target) requireEntity(raw, "caption-entities", step.target.captionId);
|
|
4774
4877
|
else requireSegment(raw, step.target.audioScriptId, step.target.segmentId);
|
|
4775
4878
|
assertSelectionsAfter(raw, before, tracked, steps);
|
|
4879
|
+
const changedPhonetics = new Set([...tracked.entities.get("phonetic-script-entities")?.keys() ?? [], ...steps.flatMap((step) => step.type !== "text" && step.table === "phonetic-script-entities" ? [step.id] : [])]);
|
|
4880
|
+
for (const id of changedPhonetics) {
|
|
4881
|
+
const row = raw["phonetic-script-entities"][id];
|
|
4882
|
+
phoneticRows.set(id, row ? copyInput(row) : void 0);
|
|
4883
|
+
if (!row) continue;
|
|
4884
|
+
const old = nativeBefore["phonetic-script-entities"][id];
|
|
4885
|
+
if (old) native["phonetic-script-entities"][id] = old;
|
|
4886
|
+
else delete native["phonetic-script-entities"][id];
|
|
4887
|
+
}
|
|
4776
4888
|
for (const [id, fields] of tracked.entities.get("caption-entities") ?? []) {
|
|
4777
4889
|
const row = raw["caption-entities"][id];
|
|
4778
4890
|
if (fields.has("text") && row?.text !== void 0 && before["caption-entities"][id]?.text === void 0) {
|
|
@@ -4781,6 +4893,7 @@ function runTransaction(doc, mirror, edit, options, setReject) {
|
|
|
4781
4893
|
}
|
|
4782
4894
|
}
|
|
4783
4895
|
for (const table of Object.keys(selectionField)) {
|
|
4896
|
+
if (table === "phonetic-script-entities") continue;
|
|
4784
4897
|
const field = selectionField[table];
|
|
4785
4898
|
for (const [id, fields] of tracked.entities.get(table) ?? []) {
|
|
4786
4899
|
const row = raw[table][id];
|
|
@@ -4820,6 +4933,8 @@ function runTransaction(doc, mirror, edit, options, setReject) {
|
|
|
4820
4933
|
applyTextEdits(text, step.edits);
|
|
4821
4934
|
continue;
|
|
4822
4935
|
}
|
|
4936
|
+
const phonetic = step.table === "phonetic-script-entities" ? phoneticRows.get(step.id) : void 0;
|
|
4937
|
+
if (step.table === "phonetic-script-entities" && !phonetic) continue;
|
|
4823
4938
|
const row = entityRow(doc, step.table, step.id);
|
|
4824
4939
|
const field = selectionField[step.table];
|
|
4825
4940
|
if (step.type === "range") {
|
|
@@ -4838,12 +4953,21 @@ function runTransaction(doc, mirror, edit, options, setReject) {
|
|
|
4838
4953
|
if (!value.start || !value.end) throw new Error("Unable to construct prepared range");
|
|
4839
4954
|
}
|
|
4840
4955
|
if (step.phonemeScript !== void 0) value.phonemeScript = step.phonemeScript;
|
|
4841
|
-
if (
|
|
4842
|
-
|
|
4843
|
-
|
|
4956
|
+
if (phonetic) phonetic.phoneme = value;
|
|
4957
|
+
else {
|
|
4958
|
+
if (!row) throw new Error("Unable to construct prepared range");
|
|
4959
|
+
row.set(field, codecs[step.table].encode(value));
|
|
4960
|
+
}
|
|
4961
|
+
} else if (step.value !== void 0) if (phonetic) phonetic.phoneme = step.value;
|
|
4962
|
+
else {
|
|
4844
4963
|
if (!row) throw new Error("Prepared selection owner is missing");
|
|
4845
4964
|
row.set(field, codecs[step.table].encode(step.value));
|
|
4846
|
-
}
|
|
4965
|
+
}
|
|
4966
|
+
else if (row?.get(field) !== void 0) row.delete(field);
|
|
4967
|
+
}
|
|
4968
|
+
for (const [id, binding] of phoneticRows) {
|
|
4969
|
+
if (!binding) continue;
|
|
4970
|
+
(entityRow(doc, "phonetic-script-entities", id) ?? doc.getMap("phonetic-script-entities").setContainer(id, new LoroMap())).set("binding", phoneticBindingCodec.encode(binding));
|
|
4847
4971
|
}
|
|
4848
4972
|
}
|
|
4849
4973
|
});
|
|
@@ -4890,7 +5014,7 @@ function assertSelectionsAfter(raw, before, tracked, steps) {
|
|
|
4890
5014
|
if (!row) continue;
|
|
4891
5015
|
const phoneme = phonemes.has(id) ? phonemes.get(id) : row.phoneme;
|
|
4892
5016
|
const old = before["phonetic-script-entities"][id];
|
|
4893
|
-
assertPhoneticScript(old, {
|
|
5017
|
+
assertPhoneticScript(old ? { ...old } : void 0, {
|
|
4894
5018
|
...row,
|
|
4895
5019
|
phoneme: isRecord(phoneme) ? phoneme : void 0
|
|
4896
5020
|
});
|
|
@@ -4929,6 +5053,7 @@ var MedeoDsl = class MedeoDsl {
|
|
|
4929
5053
|
"tracks",
|
|
4930
5054
|
"part_library"
|
|
4931
5055
|
].some((key) => Object.hasOwn(roots, key))) throw new Error("Expected a new DSL document, not a legacy content model");
|
|
5056
|
+
assertPhoneticBindingFormat(doc);
|
|
4932
5057
|
doc.configTextStyle(textStyles);
|
|
4933
5058
|
this.mirror = new Mirror({
|
|
4934
5059
|
doc,
|
|
@@ -4992,6 +5117,11 @@ var MedeoDsl = class MedeoDsl {
|
|
|
4992
5117
|
editCaptionText(captionId, expectedBodyId, edits, audit) {
|
|
4993
5118
|
this.transact((tx) => tx.editCaptionText(captionId, edits, expectedBodyId), audit);
|
|
4994
5119
|
}
|
|
5120
|
+
/** Check the session's write capability before an Action starts host-owned resource I/O. */
|
|
5121
|
+
assertWritable() {
|
|
5122
|
+
this.assertReadyToWrite();
|
|
5123
|
+
this.options.mutationGuard?.run(() => {});
|
|
5124
|
+
}
|
|
4995
5125
|
/**
|
|
4996
5126
|
* A run inside one segment as native Cursors. Local ranges exclude insertions at their start and
|
|
4997
5127
|
* include insertions at their end. K01 remains deferred.
|
|
@@ -5024,13 +5154,7 @@ var MedeoDsl = class MedeoDsl {
|
|
|
5024
5154
|
if (this.ownsDoc) this.doc.free();
|
|
5025
5155
|
}
|
|
5026
5156
|
mutate(run) {
|
|
5027
|
-
this.
|
|
5028
|
-
if (this.writing || this.notifying) {
|
|
5029
|
-
const error = /* @__PURE__ */ new Error("A DSL mutation is already running");
|
|
5030
|
-
this.rejectTransaction?.(error);
|
|
5031
|
-
throw error;
|
|
5032
|
-
}
|
|
5033
|
-
if (this.doc.getPendingTxnLength() !== 0) throw new Error("Commit external native edits before a DSL mutation");
|
|
5157
|
+
this.assertReadyToWrite();
|
|
5034
5158
|
const apply = () => {
|
|
5035
5159
|
this.writing = true;
|
|
5036
5160
|
try {
|
|
@@ -5045,6 +5169,15 @@ var MedeoDsl = class MedeoDsl {
|
|
|
5045
5169
|
if (this.options.mutationGuard) this.options.mutationGuard.run(apply);
|
|
5046
5170
|
else apply();
|
|
5047
5171
|
}
|
|
5172
|
+
assertReadyToWrite() {
|
|
5173
|
+
this.assertActive();
|
|
5174
|
+
if (this.writing || this.notifying) {
|
|
5175
|
+
const error = /* @__PURE__ */ new Error("A DSL mutation is already running");
|
|
5176
|
+
this.rejectTransaction?.(error);
|
|
5177
|
+
throw error;
|
|
5178
|
+
}
|
|
5179
|
+
if (this.doc.getPendingTxnLength() !== 0) throw new Error("Commit external native edits before a DSL mutation");
|
|
5180
|
+
}
|
|
5048
5181
|
notify() {
|
|
5049
5182
|
if (this.disposed || !this.dirty) return;
|
|
5050
5183
|
this.dirty = false;
|
|
@@ -5769,8 +5902,12 @@ var DslEditor = class {
|
|
|
5769
5902
|
* it; an unchanged one keeps its file. Recordings already spoken from it keep their derived-from.
|
|
5770
5903
|
*/
|
|
5771
5904
|
async setPhoneticScript(input, options) {
|
|
5905
|
+
this.dsl.assertWritable();
|
|
5772
5906
|
const id = input.phoneticScriptId ?? this.idFactory("phonetic-script");
|
|
5773
5907
|
const range = segmentRange(input);
|
|
5908
|
+
assertId(id);
|
|
5909
|
+
assertSegmentRange(range, requireSegment(this.dsl.getSnapshot(), range.audioScriptId, range.segmentId).text);
|
|
5910
|
+
assertPhonemeScript(input.phonemeScript);
|
|
5774
5911
|
const file = input.phonemeScript === void 0 ? {} : await this.fileFor(id, input.phonemeScript);
|
|
5775
5912
|
const exists = Object.hasOwn(this.dsl.getSnapshot()["phonetic-script-entities"], id);
|
|
5776
5913
|
const cleared = {
|
package/dist/dsl.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { A as MedeoDslDraft, C as UnsupportedDocumentFormatError, D as captionContentCodec, E as InvalidAtomic, F as ClipSource, I as DslClipUpdate, L as MoveDslClipsInput, M as medeoDslLoroShape, N as AddDslClip, O as isInvalidAtomic, P as AddDslClipsInput, R as ReplaceDslClipsInput, S as DslTransaction, T as documentFormat, _ as VoiceoverCaptionInput, a as toAudioScriptViews, b as MedeoDsl, c as resolveDslLayout, d as DslProjectionError, f as DslTrackLayout, g as ApplyVoiceoverInput, h as UploadText, i as AudioScriptView, j as MedeoDslLoroState, k as timeAnchorCodec, l as DslClipLayout, m as DslEditor, n as ImportedVideoDraft, o as VideoDraftProjection, p as createInitialMedeoDsl, r as fromVideoDraft, s as toVideoDraft, t as FromVideoDraftOptions, u as DslLayout, v as VoiceoverResult, w as assertDslDocument, x as DslAudit, y as CreateMedeoDslOptions, z as ClipPlacement } from "./index-
|
|
1
|
+
import { $ as TextMark, A as DeepReadonly, C as CaptionContent, D as Clip, E as CaptionText, F as EntityTables, G as RelationValues, H as RelationMutation, I as EntityValues, K as ResourceSystem, L as FieldPatch, M as DslMutation, N as EntityMutation, O as ContainMutation, P as EntityTable, Q as TextEdit, R as MedeoDslSnapshot, S as Caption, T as CaptionStyle, U as RelationTable, W as RelationTables, X as StoredFile, Z as TextDelta, _ as defaultIdFactory, a as VideoDraftCaptionStyle, at as Voice, b as tupleHash, c as VideoDraftInput, d as VideoDraftTrack, et as TextMutation, f as VideoDraftTrackItem, g as EntityIdKind, h as DslIdFactory, i as VideoDraft, it as TrackRole, j as DslDiagnostic, k as ContainNode, l as VideoDraftPartUnion, m as OpActor, n as DEFAULT_UNIT_TIME_MS, nt as TimeAnchor, o as VideoDraftContent, p as CommitOptions, q as RichTextSnapshot, r as VideoCreationSettings, rt as Track, s as VideoDraftContentPartUnion, t as CaptionDisplayCue, tt as TextRun, u as VideoDraftTimeline, v as relationId, w as CaptionSelection, x as AudioScript, y as resourceId, z as Media } from "./video-draft-types-slnHaNs9.js";
|
|
2
|
+
import { A as MedeoDslDraft, C as UnsupportedDocumentFormatError, D as captionContentCodec, E as InvalidAtomic, F as ClipSource, I as DslClipUpdate, L as MoveDslClipsInput, M as medeoDslLoroShape, N as AddDslClip, O as isInvalidAtomic, P as AddDslClipsInput, R as ReplaceDslClipsInput, S as DslTransaction, T as documentFormat, _ as VoiceoverCaptionInput, a as toAudioScriptViews, b as MedeoDsl, c as resolveDslLayout, d as DslProjectionError, f as DslTrackLayout, g as ApplyVoiceoverInput, h as UploadText, i as AudioScriptView, j as MedeoDslLoroState, k as timeAnchorCodec, l as DslClipLayout, m as DslEditor, n as ImportedVideoDraft, o as VideoDraftProjection, p as createInitialMedeoDsl, r as fromVideoDraft, s as toVideoDraft, t as FromVideoDraftOptions, u as DslLayout, v as VoiceoverResult, w as assertDslDocument, x as DslAudit, y as CreateMedeoDslOptions, z as ClipPlacement } from "./index-CmuDB_Gm.js";
|
|
3
3
|
export { type AddDslClip, type AddDslClipsInput, type ApplyVoiceoverInput, type AudioScript, type AudioScriptView, type Caption, type CaptionContent, type CaptionDisplayCue, type CaptionSelection, type CaptionStyle, type CaptionText, type Clip, type ClipPlacement, type ClipSource, type CommitOptions, type ContainMutation, type ContainNode, type CreateMedeoDslOptions, DEFAULT_UNIT_TIME_MS, type DeepReadonly, type DslAudit, type DslClipLayout, type DslClipUpdate, type DslDiagnostic, DslEditor, type DslIdFactory, type DslLayout, type DslMutation, DslProjectionError, type DslTrackLayout, type DslTransaction, type EntityIdKind, type EntityMutation, type EntityTable, type EntityTables, type EntityValues, type FieldPatch, type FromVideoDraftOptions, type ImportedVideoDraft, type InvalidAtomic, MedeoDsl, type MedeoDslDraft, type MedeoDslLoroState, type MedeoDslSnapshot, type Media, type MoveDslClipsInput, type OpActor, type RelationMutation, type RelationTable, type RelationTables, type RelationValues, type ReplaceDslClipsInput, type ResourceSystem, type RichTextSnapshot, type StoredFile, type TextDelta, type TextEdit, type TextMark, type TextMutation, type TextRun, type TimeAnchor, type Track, type TrackRole, UnsupportedDocumentFormatError, type UploadText, type VideoCreationSettings, type VideoDraft, type VideoDraftCaptionStyle, type VideoDraftContent, type VideoDraftContentPartUnion, type VideoDraftInput, type VideoDraftPartUnion, type VideoDraftProjection, type VideoDraftTimeline, type VideoDraftTrack, type VideoDraftTrackItem, type Voice, type VoiceoverCaptionInput, type VoiceoverResult, assertDslDocument, captionContentCodec, createInitialMedeoDsl, defaultIdFactory, documentFormat, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, relationId, resolveDslLayout, resourceId, timeAnchorCodec, toAudioScriptViews, toVideoDraft, tupleHash };
|
package/dist/dsl.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as toAudioScriptViews, c as DslProjectionError, i as DslEditor, n as toVideoDraft, o as MedeoDsl, r as createInitialMedeoDsl, s as resolveDslLayout, t as fromVideoDraft } from "./dsl-
|
|
1
|
+
import { St as tupleHash, bt as relationId, c as captionContentCodec, f as timeAnchorCodec, i as assertDslDocument, l as isInvalidAtomic, o as documentFormat, r as UnsupportedDocumentFormatError, s as medeoDslLoroShape, t as DEFAULT_UNIT_TIME_MS, xt as resourceId, yt as defaultIdFactory } from "./video-draft-types-DRGBN0we.js";
|
|
2
|
+
import { a as toAudioScriptViews, c as DslProjectionError, i as DslEditor, n as toVideoDraft, o as MedeoDsl, r as createInitialMedeoDsl, s as resolveDslLayout, t as fromVideoDraft } from "./dsl-Bvv_51Ns.js";
|
|
3
3
|
export { DEFAULT_UNIT_TIME_MS, DslEditor, DslProjectionError, MedeoDsl, UnsupportedDocumentFormatError, assertDslDocument, captionContentCodec, createInitialMedeoDsl, defaultIdFactory, documentFormat, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, relationId, resolveDslLayout, resourceId, timeAnchorCodec, toAudioScriptViews, toVideoDraft, tupleHash };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { b as MedeoDsl, h as UploadText, i as AudioScriptView, m as DslEditor, o as VideoDraftProjection } from "./index-
|
|
3
|
-
import { _ as ManualSyncTransport, a as MengineDocSessionOptions, g as ManualSyncDocOptions, n as DocumentSession, r as DocumentSessionUpdateEvent } from "./index-
|
|
1
|
+
import { K as ResourceSystem, R as MedeoDslSnapshot, it as TrackRole } from "./video-draft-types-slnHaNs9.js";
|
|
2
|
+
import { b as MedeoDsl, h as UploadText, i as AudioScriptView, m as DslEditor, o as VideoDraftProjection } from "./index-CmuDB_Gm.js";
|
|
3
|
+
import { P as MengineDraftResponse, _ as ManualSyncTransport, a as MengineDocSessionOptions, g as ManualSyncDocOptions, n as DocumentSession, r as DocumentSessionUpdateEvent } from "./index-BOgr8p8C.js";
|
|
4
4
|
|
|
5
5
|
//#region src/manual-sync/manual-sync-doc.d.ts
|
|
6
6
|
/** Explicit synchronization over the same DSL/editor used by the live Session. */
|
|
@@ -180,6 +180,8 @@ declare class ManualSyncDoc extends ManualSyncTransport {
|
|
|
180
180
|
}[];
|
|
181
181
|
};
|
|
182
182
|
projectVideoDraft(): VideoDraftProjection;
|
|
183
|
+
/** Read the acknowledged server revision; without a new push, confirm against the current server view. */
|
|
184
|
+
readPersistedDraft(updateSeq?: number): Promise<MengineDraftResponse>;
|
|
183
185
|
dispose(): void;
|
|
184
186
|
}
|
|
185
187
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { j as DslDiagnostic, o as VideoDraftContent, p as CommitOptions } from "./video-draft-types-
|
|
1
|
+
import { j as DslDiagnostic, o as VideoDraftContent, p as CommitOptions } from "./video-draft-types-slnHaNs9.js";
|
|
2
2
|
import { LoroDoc, PeerID, VersionVector } from "loro-crdt";
|
|
3
3
|
import { DocState, LocalSaveState } from "@mengine/sync";
|
|
4
4
|
import { BaseDocStorage, Connection, DocDiff, DocPushReceipt, DocSnapshotRecord, DocStorage, DocStorageOptions, DocUpdate, DocUpdateRecord } from "@mengine/storage";
|
|
@@ -255,7 +255,7 @@ type PushResultKind = 'ack' | 'duplicate' | 'rejected' | 'failed' | 'nothing_to_
|
|
|
255
255
|
*/
|
|
256
256
|
interface PushResult {
|
|
257
257
|
kind: PushResultKind;
|
|
258
|
-
/** Server
|
|
258
|
+
/** Server sequence from an `ack`/`duplicate`, retained on an idle retry so its revision can be verified. */
|
|
259
259
|
mengineUpdateSeq?: number | undefined;
|
|
260
260
|
/** @deprecated Ack-only sequence retained until consumers adopt `mengineUpdateSeq`. */
|
|
261
261
|
updateSeq?: number | undefined;
|
|
@@ -301,10 +301,12 @@ interface ManualSyncDocOptions {
|
|
|
301
301
|
}
|
|
302
302
|
/** Shared explicit pull/push lifecycle; model-specific editors never implement transport. */
|
|
303
303
|
declare class ManualSyncTransport {
|
|
304
|
-
|
|
304
|
+
protected readonly client: MengineHttpClient;
|
|
305
305
|
protected readonly doc: LoroDoc;
|
|
306
306
|
private watermark;
|
|
307
307
|
private disposed;
|
|
308
|
+
/** A retry with no new bytes still verifies the revision from its last durable receipt. */
|
|
309
|
+
private confirmedSequence?;
|
|
308
310
|
protected constructor(client: MengineHttpClient, doc: LoroDoc, watermark: VersionVector);
|
|
309
311
|
editorPeerId(): PeerID;
|
|
310
312
|
protected assertActive(): void;
|
|
@@ -581,6 +583,7 @@ type DocumentSessionModel<Snapshot, Editor, Document> = (doc: LoroDoc, guard: Do
|
|
|
581
583
|
declare class DocumentSession<Snapshot, Editor, Document> {
|
|
582
584
|
private readonly options;
|
|
583
585
|
private readonly model;
|
|
586
|
+
private readonly validateDocument;
|
|
584
587
|
private readonly docId;
|
|
585
588
|
private readonly local;
|
|
586
589
|
private readonly server;
|
|
@@ -607,7 +610,7 @@ declare class DocumentSession<Snapshot, Editor, Document> {
|
|
|
607
610
|
* doc (e.g. nothing was edited since the last confirmed push).
|
|
608
611
|
*/
|
|
609
612
|
private serverVVValue;
|
|
610
|
-
constructor(options: MengineDocSessionOptions, model: DocumentSessionModel<Snapshot, Editor, Document
|
|
613
|
+
constructor(options: MengineDocSessionOptions, model: DocumentSessionModel<Snapshot, Editor, Document>, validateDocument: (doc: LoroDoc) => void);
|
|
611
614
|
/**
|
|
612
615
|
* Observe every push verdict, including `duplicate` and failures.
|
|
613
616
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as PhonemeSelection, J as
|
|
1
|
+
import { B as PhonemeSelection, J as SegmentRange, L as FieldPatch, M as DslMutation, Q as TextEdit, R as MedeoDslSnapshot, T as CaptionStyle, V as PhoneticScript, X as StoredFile, Y as SegmentSelection, at as Voice, c as VideoDraftInput, h as DslIdFactory, it as TrackRole, j as DslDiagnostic, nt as TimeAnchor, o as VideoDraftContent, p as CommitOptions, w as CaptionSelection, z as Media } from "./video-draft-types-slnHaNs9.js";
|
|
2
2
|
import { ContainerType, Cursor, LoroDoc, PeerID, TreeID } from "loro-crdt";
|
|
3
3
|
|
|
4
4
|
//#region src/dsl/action-context.d.ts
|
|
@@ -483,20 +483,12 @@ declare const medeoDslLoroShape: RootSchemaType<{
|
|
|
483
483
|
options: {};
|
|
484
484
|
};
|
|
485
485
|
'phonetic-script-entities': LoroMapSchemaWithCatchall<{}, LoroMapSchema<{
|
|
486
|
-
|
|
487
|
-
system: /*elided*/any;
|
|
488
|
-
key: /*elided*/any;
|
|
489
|
-
storageKey: /*elided*/any;
|
|
490
|
-
digest: /*elided*/any;
|
|
486
|
+
binding: /*elided*/any;
|
|
491
487
|
}> & {
|
|
492
488
|
options: {};
|
|
493
489
|
} & {
|
|
494
490
|
catchall: <C extends SchemaType>(catchallSchema: C) => LoroMapSchemaWithCatchall<{
|
|
495
|
-
|
|
496
|
-
system: /*elided*/any;
|
|
497
|
-
key: /*elided*/any;
|
|
498
|
-
storageKey: /*elided*/any;
|
|
499
|
-
digest: /*elided*/any;
|
|
491
|
+
binding: /*elided*/any;
|
|
500
492
|
}, C>;
|
|
501
493
|
}> & {
|
|
502
494
|
options: {};
|
|
@@ -589,8 +581,9 @@ type ContainDraftNode = Omit<Input['contain-relations'][number], 'id' | 'childre
|
|
|
589
581
|
children: ContainDraftNode[];
|
|
590
582
|
};
|
|
591
583
|
type DraftFields<T> = T extends Cursor ? T : T extends (infer Item)[] ? DraftFields<Item>[] : T extends object ? { [K in keyof T as undefined extends T[K] ? never : K]: DraftFields<T[K]> } & { [K in keyof T as undefined extends T[K] ? K : never]?: DraftFields<T[K]> } : T;
|
|
592
|
-
type MedeoDslDraft = DraftFields<Omit<Input, 'contain-relations'>> & {
|
|
584
|
+
type MedeoDslDraft = DraftFields<Omit<Input, 'contain-relations' | 'phonetic-script-entities'>> & {
|
|
593
585
|
'contain-relations': ContainDraftNode[];
|
|
586
|
+
'phonetic-script-entities': Record<string, PhoneticScript>;
|
|
594
587
|
};
|
|
595
588
|
//#endregion
|
|
596
589
|
//#region ../medeo-dsl/src/schema/codec.d.ts
|
|
@@ -614,7 +607,7 @@ declare const captionContentCodec: AtomicCodec<SegmentSelection>;
|
|
|
614
607
|
declare function documentFormat(doc: LoroDoc): 'dsl' | 'legacy' | 'mixed' | 'unknown';
|
|
615
608
|
declare class UnsupportedDocumentFormatError extends Error {
|
|
616
609
|
readonly code = "unsupported_document_format";
|
|
617
|
-
constructor();
|
|
610
|
+
constructor(message?: string);
|
|
618
611
|
}
|
|
619
612
|
/** Run after initial import, before opening an editable handle. Empty new documents still have one Timeline. */
|
|
620
613
|
declare function assertDslDocument(doc: LoroDoc): void;
|
|
@@ -691,6 +684,8 @@ declare class MedeoDsl {
|
|
|
691
684
|
applyMutations(mutations: readonly DslMutation[], audit: DslAudit): void;
|
|
692
685
|
editText(scriptId: string, segmentId: string, expectedBodyId: string, edits: readonly TextEdit[], audit: DslAudit): void;
|
|
693
686
|
editCaptionText(captionId: string, expectedBodyId: string, edits: readonly TextEdit[], audit: DslAudit): void;
|
|
687
|
+
/** Check the session's write capability before an Action starts host-owned resource I/O. */
|
|
688
|
+
assertWritable(): void;
|
|
694
689
|
/**
|
|
695
690
|
* A run inside one segment as native Cursors. Local ranges exclude insertions at their start and
|
|
696
691
|
* include insertions at their end. K01 remains deferred.
|
|
@@ -698,6 +693,7 @@ declare class MedeoDsl {
|
|
|
698
693
|
textRange(scriptId: string, segmentId: string, start: number, end: number): SegmentSelection;
|
|
699
694
|
dispose(): void;
|
|
700
695
|
private mutate;
|
|
696
|
+
private assertReadyToWrite;
|
|
701
697
|
private notify;
|
|
702
698
|
private assertActive;
|
|
703
699
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { A as MedeoDslDraft, C as UnsupportedDocumentFormatError, D as captionContentCodec, E as InvalidAtomic, F as ClipSource, I as DslClipUpdate, L as MoveDslClipsInput, M as medeoDslLoroShape, N as AddDslClip, O as isInvalidAtomic, P as AddDslClipsInput, R as ReplaceDslClipsInput, S as DslTransaction, T as documentFormat, _ as VoiceoverCaptionInput, a as toAudioScriptViews, b as MedeoDsl, c as resolveDslLayout, d as DslProjectionError, f as DslTrackLayout, g as ApplyVoiceoverInput, h as UploadText, i as AudioScriptView, j as MedeoDslLoroState, k as timeAnchorCodec, l as DslClipLayout, m as DslEditor, n as ImportedVideoDraft, o as VideoDraftProjection, p as createInitialMedeoDsl, r as fromVideoDraft, s as toVideoDraft, t as FromVideoDraftOptions, u as DslLayout, v as VoiceoverResult, w as assertDslDocument, x as DslAudit, y as CreateMedeoDslOptions, z as ClipPlacement } from "./index-
|
|
3
|
-
import { A as MenginePushRejectedError, B as MengineSyncResponse, C as PushResult, D as MengineHttpClient, E as readMengineEventStream, F as MenginePushResponse, H as base64ToBytes, I as MenginePushUpdateResponse, L as MengineRejectedResponse, M as MengineAuditResponse, N as MengineDocumentVersion, O as MengineHttpClientOptions, P as MengineDraftResponse, R as MengineSnapshotResponse, S as PullResult, T as MengineEventStreamOptions, U as bytesToBase64, V as MengineUpdateMeta, a as MengineDocSessionOptions, b as DocVersionMark, c as WaitForLocalSaveOptions, d as MengineUndoState, f as MedeoHttpDocStorage, g as ManualSyncDocOptions, h as PushOutcomeKind, i as MengineAckFailedError, j as MengineAuditEntry, k as MengineHttpRequestError, l as WaitForServerAckOptions, m as PushOutcome, o as MengineDocSyncState, p as MedeoHttpDocStorageOptions, s as MengineLocalSaveState, t as MemoryDocStorage, u as DocStorageLike, v as decodeDocVersionMark, w as PushResultKind, x as PullFailureReason, y as encodeDocVersionMark, z as MengineSseUpdateEvent } from "./index-
|
|
4
|
-
import { n as MengineDocSessionUpdateEvent, r as ManualSyncDoc, t as MengineDocSession } from "./index-
|
|
1
|
+
import { $ as TextMark, A as DeepReadonly, C as CaptionContent, D as Clip, E as CaptionText, F as EntityTables, G as RelationValues, H as RelationMutation, I as EntityValues, K as ResourceSystem, L as FieldPatch, M as DslMutation, N as EntityMutation, O as ContainMutation, P as EntityTable, Q as TextEdit, R as MedeoDslSnapshot, S as Caption, T as CaptionStyle, U as RelationTable, W as RelationTables, X as StoredFile, Z as TextDelta, _ as defaultIdFactory, a as VideoDraftCaptionStyle, at as Voice, b as tupleHash, c as VideoDraftInput, d as VideoDraftTrack, et as TextMutation, f as VideoDraftTrackItem, g as EntityIdKind, h as DslIdFactory, i as VideoDraft, it as TrackRole, j as DslDiagnostic, k as ContainNode, l as VideoDraftPartUnion, m as OpActor, n as DEFAULT_UNIT_TIME_MS, nt as TimeAnchor, o as VideoDraftContent, p as CommitOptions, q as RichTextSnapshot, r as VideoCreationSettings, rt as Track, s as VideoDraftContentPartUnion, t as CaptionDisplayCue, tt as TextRun, u as VideoDraftTimeline, v as relationId, w as CaptionSelection, x as AudioScript, y as resourceId, z as Media } from "./video-draft-types-slnHaNs9.js";
|
|
2
|
+
import { A as MedeoDslDraft, C as UnsupportedDocumentFormatError, D as captionContentCodec, E as InvalidAtomic, F as ClipSource, I as DslClipUpdate, L as MoveDslClipsInput, M as medeoDslLoroShape, N as AddDslClip, O as isInvalidAtomic, P as AddDslClipsInput, R as ReplaceDslClipsInput, S as DslTransaction, T as documentFormat, _ as VoiceoverCaptionInput, a as toAudioScriptViews, b as MedeoDsl, c as resolveDslLayout, d as DslProjectionError, f as DslTrackLayout, g as ApplyVoiceoverInput, h as UploadText, i as AudioScriptView, j as MedeoDslLoroState, k as timeAnchorCodec, l as DslClipLayout, m as DslEditor, n as ImportedVideoDraft, o as VideoDraftProjection, p as createInitialMedeoDsl, r as fromVideoDraft, s as toVideoDraft, t as FromVideoDraftOptions, u as DslLayout, v as VoiceoverResult, w as assertDslDocument, x as DslAudit, y as CreateMedeoDslOptions, z as ClipPlacement } from "./index-CmuDB_Gm.js";
|
|
3
|
+
import { A as MenginePushRejectedError, B as MengineSyncResponse, C as PushResult, D as MengineHttpClient, E as readMengineEventStream, F as MenginePushResponse, H as base64ToBytes, I as MenginePushUpdateResponse, L as MengineRejectedResponse, M as MengineAuditResponse, N as MengineDocumentVersion, O as MengineHttpClientOptions, P as MengineDraftResponse, R as MengineSnapshotResponse, S as PullResult, T as MengineEventStreamOptions, U as bytesToBase64, V as MengineUpdateMeta, a as MengineDocSessionOptions, b as DocVersionMark, c as WaitForLocalSaveOptions, d as MengineUndoState, f as MedeoHttpDocStorage, g as ManualSyncDocOptions, h as PushOutcomeKind, i as MengineAckFailedError, j as MengineAuditEntry, k as MengineHttpRequestError, l as WaitForServerAckOptions, m as PushOutcome, o as MengineDocSyncState, p as MedeoHttpDocStorageOptions, s as MengineLocalSaveState, t as MemoryDocStorage, u as DocStorageLike, v as decodeDocVersionMark, w as PushResultKind, x as PullFailureReason, y as encodeDocVersionMark, z as MengineSseUpdateEvent } from "./index-BOgr8p8C.js";
|
|
4
|
+
import { n as MengineDocSessionUpdateEvent, r as ManualSyncDoc, t as MengineDocSession } from "./index-BGEcTwoD.js";
|
|
5
5
|
export { type AddDslClip, type AddDslClipsInput, type ApplyVoiceoverInput, type AudioScript, type AudioScriptView, type Caption, type CaptionContent, type CaptionDisplayCue, type CaptionSelection, type CaptionStyle, type CaptionText, type Clip, type ClipPlacement, type ClipSource, type CommitOptions, type ContainMutation, type ContainNode, type CreateMedeoDslOptions, DEFAULT_UNIT_TIME_MS, type DeepReadonly, type DocStorageLike, type DocVersionMark, type DslAudit, type DslClipLayout, type DslClipUpdate, type DslDiagnostic, DslEditor, type DslIdFactory, type DslLayout, type DslMutation, DslProjectionError, type DslTrackLayout, type DslTransaction, type EntityIdKind, type EntityMutation, type EntityTable, type EntityTables, type EntityValues, type FieldPatch, type FromVideoDraftOptions, type ImportedVideoDraft, type InvalidAtomic, ManualSyncDoc, type ManualSyncDocOptions, MedeoDsl, type MedeoDslDraft, type MedeoDslLoroState, type MedeoDslSnapshot, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type Media, MemoryDocStorage, MengineAckFailedError, type MengineAuditEntry, type MengineAuditResponse, MengineDocSession, type MengineDocSessionOptions, type MengineDocSessionUpdateEvent, type MengineDocSyncState, type MengineDocumentVersion, type MengineDraftResponse, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, type MengineLocalSaveState, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUndoState, type MengineUpdateMeta, type MoveDslClipsInput, type OpActor, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, type RelationMutation, type RelationTable, type RelationTables, type RelationValues, type ReplaceDslClipsInput, type ResourceSystem, type RichTextSnapshot, type StoredFile, type TextDelta, type TextEdit, type TextMark, type TextMutation, type TextRun, type TimeAnchor, type Track, type TrackRole, UnsupportedDocumentFormatError, type UploadText, type VideoCreationSettings, type VideoDraft, type VideoDraftCaptionStyle, type VideoDraftContent, type VideoDraftContentPartUnion, type VideoDraftInput, type VideoDraftPartUnion, type VideoDraftProjection, type VideoDraftTimeline, type VideoDraftTrack, type VideoDraftTrackItem, type Voice, type VoiceoverCaptionInput, type VoiceoverResult, type WaitForLocalSaveOptions, type WaitForServerAckOptions, assertDslDocument, base64ToBytes, bytesToBase64, captionContentCodec, createInitialMedeoDsl, decodeDocVersionMark, defaultIdFactory, documentFormat, encodeDocVersionMark, fromVideoDraft, isInvalidAtomic, medeoDslLoroShape, readMengineEventStream, relationId, resolveDslLayout, resourceId, timeAnchorCodec, toAudioScriptViews, toVideoDraft, tupleHash };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as bytesToBase64, t as base64ToBytes } from "./base64-D-jd-dr5.js";
|
|
2
|
-
import { a as covers, c as readMengineEventStream, d as MenginePushRejectedError, i as openManualDocument, l as MengineHttpClient, n as MedeoHttpDocStorage, o as decodeDocVersionMark, r as ManualSyncTransport, s as encodeDocVersionMark, t as MemoryDocStorage, u as MengineHttpRequestError } from "./storage-
|
|
3
|
-
import {
|
|
4
|
-
import { a as toAudioScriptViews, c as DslProjectionError, i as DslEditor, n as toVideoDraft, o as MedeoDsl, r as createInitialMedeoDsl, s as resolveDslLayout, t as fromVideoDraft } from "./dsl-
|
|
5
|
-
import { UndoManager, VersionVector, decodeImportBlobMeta } from "loro-crdt";
|
|
2
|
+
import { a as covers, c as readMengineEventStream, d as MenginePushRejectedError, i as openManualDocument, l as MengineHttpClient, n as MedeoHttpDocStorage, o as decodeDocVersionMark, r as ManualSyncTransport, s as encodeDocVersionMark, t as MemoryDocStorage, u as MengineHttpRequestError } from "./storage-evqvKS4B.js";
|
|
3
|
+
import { St as tupleHash, bt as relationId, c as captionContentCodec, f as timeAnchorCodec, i as assertDslDocument, l as isInvalidAtomic, o as documentFormat, r as UnsupportedDocumentFormatError, s as medeoDslLoroShape, t as DEFAULT_UNIT_TIME_MS, xt as resourceId, yt as defaultIdFactory } from "./video-draft-types-DRGBN0we.js";
|
|
4
|
+
import { a as toAudioScriptViews, c as DslProjectionError, i as DslEditor, n as toVideoDraft, o as MedeoDsl, r as createInitialMedeoDsl, s as resolveDslLayout, t as fromVideoDraft } from "./dsl-Bvv_51Ns.js";
|
|
5
|
+
import { LoroDoc, UndoManager, VersionVector, decodeImportBlobMeta } from "loro-crdt";
|
|
6
6
|
import { ClientServerSynchronizer, DocManager } from "@mengine/sync";
|
|
7
7
|
import { DisposableSet, EventBus } from "@mengine/utils";
|
|
8
8
|
//#region src/manual-sync/manual-sync-doc.ts
|
|
@@ -27,6 +27,15 @@ var ManualSyncDoc = class ManualSyncDoc extends ManualSyncTransport {
|
|
|
27
27
|
projectVideoDraft() {
|
|
28
28
|
return toVideoDraft(this.snapshot());
|
|
29
29
|
}
|
|
30
|
+
/** Read the acknowledged server revision; without a new push, confirm against the current server view. */
|
|
31
|
+
async readPersistedDraft(updateSeq) {
|
|
32
|
+
this.assertActive();
|
|
33
|
+
const result = updateSeq === void 0 ? await this.client.fetchDraft() : await this.client.fetchDraftAt(updateSeq);
|
|
34
|
+
this.assertActive();
|
|
35
|
+
if (updateSeq !== void 0 && result.version.update_seq !== updateSeq) throw new Error("The projected revision does not match the push receipt");
|
|
36
|
+
if (!covers(VersionVector.decode(base64ToBytes(result.version.server_vv)), this.doc.oplogVersion())) throw new Error("The projected server revision does not hold the local update");
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
30
39
|
dispose() {
|
|
31
40
|
this.dsl.dispose();
|
|
32
41
|
super.dispose();
|
|
@@ -209,6 +218,7 @@ var MengineAckFailedError = class extends Error {
|
|
|
209
218
|
var DocumentSession = class {
|
|
210
219
|
options;
|
|
211
220
|
model;
|
|
221
|
+
validateDocument;
|
|
212
222
|
docId;
|
|
213
223
|
local;
|
|
214
224
|
server;
|
|
@@ -235,9 +245,10 @@ var DocumentSession = class {
|
|
|
235
245
|
* doc (e.g. nothing was edited since the last confirmed push).
|
|
236
246
|
*/
|
|
237
247
|
serverVVValue = null;
|
|
238
|
-
constructor(options, model) {
|
|
248
|
+
constructor(options, model, validateDocument) {
|
|
239
249
|
this.options = options;
|
|
240
250
|
this.model = model;
|
|
251
|
+
this.validateDocument = validateDocument;
|
|
241
252
|
this.mutationGuard = new DocumentMutationGuard(options.readonlyMode);
|
|
242
253
|
this.docId = options.docId;
|
|
243
254
|
this.local = options.localStorage ?? new MemoryDocStorage();
|
|
@@ -441,6 +452,17 @@ var DocumentSession = class {
|
|
|
441
452
|
await this.local.connection.waitForConnected().abortOn(this.lifetime.signal);
|
|
442
453
|
if (this.destroyed) throw new Error("mengine doc session destroyed");
|
|
443
454
|
if (this.options.initialSnapshot) {
|
|
455
|
+
const preview = new LoroDoc();
|
|
456
|
+
try {
|
|
457
|
+
if (preview.import(this.options.initialSnapshot).pending) throw new Error("Snapshot has missing dependencies");
|
|
458
|
+
this.validateDocument(preview);
|
|
459
|
+
const cached = await this.local.getDoc(this.docId);
|
|
460
|
+
if (cached && preview.import(cached.data).pending) throw new Error("Cached document has missing dependencies");
|
|
461
|
+
this.validateDocument(preview);
|
|
462
|
+
} finally {
|
|
463
|
+
preview.free();
|
|
464
|
+
}
|
|
465
|
+
if (this.destroyed) throw new Error("mengine doc session destroyed");
|
|
444
466
|
await this.local.pushDocUpdate({
|
|
445
467
|
docId: this.docId,
|
|
446
468
|
data: this.options.initialSnapshot
|
|
@@ -637,7 +659,7 @@ var MengineDocSession = class extends DocumentSession {
|
|
|
637
659
|
subscribe: (listener) => dsl.subscribe(listener),
|
|
638
660
|
dispose: () => dsl.dispose()
|
|
639
661
|
};
|
|
640
|
-
});
|
|
662
|
+
}, assertDslDocument);
|
|
641
663
|
}
|
|
642
664
|
get dsl() {
|
|
643
665
|
return this.document;
|
package/dist/legacy.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as VideoDraft, l as VideoDraftPartUnion, o as VideoDraftContent, p as CommitOptions, t as CaptionDisplayCue } from "./video-draft-types-
|
|
2
|
-
import { A as MenginePushRejectedError, B as MengineSyncResponse, C as PushResult, D as MengineHttpClient, E as readMengineEventStream, F as MenginePushResponse, H as base64ToBytes, I as MenginePushUpdateResponse, L as MengineRejectedResponse, M as MengineAuditResponse, N as MengineDocumentVersion, O as MengineHttpClientOptions, P as MengineDraftResponse, R as MengineSnapshotResponse, S as PullResult, T as MengineEventStreamOptions, U as bytesToBase64, V as MengineUpdateMeta, _ as ManualSyncTransport, a as MengineDocSessionOptions, b as DocVersionMark, d as MengineUndoState, f as MedeoHttpDocStorage, g as ManualSyncDocOptions, h as PushOutcomeKind, j as MengineAuditEntry, k as MengineHttpRequestError, l as WaitForServerAckOptions, m as PushOutcome, o as MengineDocSyncState, p as MedeoHttpDocStorageOptions, t as MemoryDocStorage, u as DocStorageLike, v as decodeDocVersionMark, w as PushResultKind, x as PullFailureReason, y as encodeDocVersionMark, z as MengineSseUpdateEvent } from "./index-
|
|
1
|
+
import { i as VideoDraft, l as VideoDraftPartUnion, o as VideoDraftContent, p as CommitOptions, t as CaptionDisplayCue } from "./video-draft-types-slnHaNs9.js";
|
|
2
|
+
import { A as MenginePushRejectedError, B as MengineSyncResponse, C as PushResult, D as MengineHttpClient, E as readMengineEventStream, F as MenginePushResponse, H as base64ToBytes, I as MenginePushUpdateResponse, L as MengineRejectedResponse, M as MengineAuditResponse, N as MengineDocumentVersion, O as MengineHttpClientOptions, P as MengineDraftResponse, R as MengineSnapshotResponse, S as PullResult, T as MengineEventStreamOptions, U as bytesToBase64, V as MengineUpdateMeta, _ as ManualSyncTransport, a as MengineDocSessionOptions, b as DocVersionMark, d as MengineUndoState, f as MedeoHttpDocStorage, g as ManualSyncDocOptions, h as PushOutcomeKind, j as MengineAuditEntry, k as MengineHttpRequestError, l as WaitForServerAckOptions, m as PushOutcome, o as MengineDocSyncState, p as MedeoHttpDocStorageOptions, t as MemoryDocStorage, u as DocStorageLike, v as decodeDocVersionMark, w as PushResultKind, x as PullFailureReason, y as encodeDocVersionMark, z as MengineSseUpdateEvent } from "./index-BOgr8p8C.js";
|
|
3
3
|
import { LoroDoc, PeerID } from "loro-crdt";
|
|
4
4
|
|
|
5
5
|
//#region ../medeo-dsl/depreacted/sandbox.d.ts
|
package/dist/legacy.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as bytesToBase64, t as base64ToBytes } from "./base64-D-jd-dr5.js";
|
|
2
|
-
import { c as readMengineEventStream, d as MenginePushRejectedError, i as openManualDocument, l as MengineHttpClient, n as MedeoHttpDocStorage, o as decodeDocVersionMark, r as ManualSyncTransport, s as encodeDocVersionMark, t as MemoryDocStorage, u as MengineHttpRequestError } from "./storage-
|
|
3
|
-
import {
|
|
2
|
+
import { c as readMengineEventStream, d as MenginePushRejectedError, i as openManualDocument, l as MengineHttpClient, n as MedeoHttpDocStorage, o as decodeDocVersionMark, r as ManualSyncTransport, s as encodeDocVersionMark, t as MemoryDocStorage, u as MengineHttpRequestError } from "./storage-evqvKS4B.js";
|
|
3
|
+
import { o as documentFormat, r as UnsupportedDocumentFormatError, t as DEFAULT_UNIT_TIME_MS } from "./video-draft-types-DRGBN0we.js";
|
|
4
4
|
import { u as volumeSchema } from "./shared-iWnU2osE.js";
|
|
5
5
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
6
6
|
import { LoroDoc, LoroMap, LoroMovableList, LoroText, UndoManager } from "loro-crdt";
|
|
@@ -293,6 +293,8 @@ var ManualSyncTransport = class {
|
|
|
293
293
|
doc;
|
|
294
294
|
watermark;
|
|
295
295
|
disposed = false;
|
|
296
|
+
/** A retry with no new bytes still verifies the revision from its last durable receipt. */
|
|
297
|
+
confirmedSequence;
|
|
296
298
|
constructor(client, doc, watermark) {
|
|
297
299
|
this.client = client;
|
|
298
300
|
this.doc = doc;
|
|
@@ -395,7 +397,8 @@ var ManualSyncTransport = class {
|
|
|
395
397
|
const localVersion = this.doc.oplogVersion();
|
|
396
398
|
if (covers(this.watermark, localVersion)) return {
|
|
397
399
|
kind: "nothing_to_push",
|
|
398
|
-
collaborated: false
|
|
400
|
+
collaborated: false,
|
|
401
|
+
...this.confirmedSequence === void 0 ? {} : { mengineUpdateSeq: this.confirmedSequence }
|
|
399
402
|
};
|
|
400
403
|
const update = this.doc.export({
|
|
401
404
|
mode: "update",
|
|
@@ -405,6 +408,7 @@ var ManualSyncTransport = class {
|
|
|
405
408
|
const response = await this.client.pushUpdate(update);
|
|
406
409
|
const serverVV = this.serverVVFrom(response.version?.server_vv);
|
|
407
410
|
if (serverVV != null) this.watermark = serverVV;
|
|
411
|
+
this.confirmedSequence = response.version?.update_seq ?? response.update_seq ?? void 0;
|
|
408
412
|
return {
|
|
409
413
|
kind: response.kind,
|
|
410
414
|
mengineUpdateSeq: response.version?.update_seq ?? response.update_seq ?? void 0,
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as VideoDraft } from "./video-draft-types-
|
|
2
|
-
import { b as MedeoDsl } from "./index-
|
|
1
|
+
import { i as VideoDraft } from "./video-draft-types-slnHaNs9.js";
|
|
2
|
+
import { b as MedeoDsl } from "./index-CmuDB_Gm.js";
|
|
3
3
|
import { LoroDoc } from "loro-crdt";
|
|
4
4
|
|
|
5
5
|
//#region src/testing/in-memory-mengine-server.d.ts
|
|
@@ -16,6 +16,7 @@ import { LoroDoc } from "loro-crdt";
|
|
|
16
16
|
declare class InMemoryMengineServer {
|
|
17
17
|
private readonly doc;
|
|
18
18
|
private readonly updates;
|
|
19
|
+
private readonly revisions;
|
|
19
20
|
private readonly subscribers;
|
|
20
21
|
private seq;
|
|
21
22
|
private hasSnapshot;
|
|
@@ -28,6 +29,7 @@ declare class InMemoryMengineServer {
|
|
|
28
29
|
readonly fetchImpl: typeof fetch;
|
|
29
30
|
private parsePath;
|
|
30
31
|
private version;
|
|
32
|
+
private handleDraft;
|
|
31
33
|
private handleSnapshot;
|
|
32
34
|
private handleBootstrap;
|
|
33
35
|
private handleSync;
|
package/dist/testing.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as bytesToBase64, t as base64ToBytes } from "./base64-D-jd-dr5.js";
|
|
2
|
-
import { a as
|
|
3
|
-
import { i as DslEditor, n as toVideoDraft, o as MedeoDsl, r as createInitialMedeoDsl } from "./dsl-
|
|
2
|
+
import { a as assertPhoneticBindingFormat, i as assertDslDocument, o as documentFormat } from "./video-draft-types-DRGBN0we.js";
|
|
3
|
+
import { i as DslEditor, n as toVideoDraft, o as MedeoDsl, r as createInitialMedeoDsl } from "./dsl-Bvv_51Ns.js";
|
|
4
4
|
import { t as classifyUpdate } from "./loro-relay-doc-Bi6JKqtQ.js";
|
|
5
5
|
import { LoroDoc, VersionVector, encodeFrontiers } from "loro-crdt";
|
|
6
6
|
//#region src/testing/in-memory-mengine-server.ts
|
|
@@ -17,6 +17,7 @@ import { LoroDoc, VersionVector, encodeFrontiers } from "loro-crdt";
|
|
|
17
17
|
var InMemoryMengineServer = class {
|
|
18
18
|
doc = new LoroDoc();
|
|
19
19
|
updates = [];
|
|
20
|
+
revisions = /* @__PURE__ */ new Map();
|
|
20
21
|
subscribers = /* @__PURE__ */ new Set();
|
|
21
22
|
seq = 0;
|
|
22
23
|
hasSnapshot = false;
|
|
@@ -40,6 +41,7 @@ var InMemoryMengineServer = class {
|
|
|
40
41
|
try {
|
|
41
42
|
this.doc.import(dsl.doc.export({ mode: "snapshot" }));
|
|
42
43
|
this.hasSnapshot = true;
|
|
44
|
+
this.revisions.set(0, this.doc.export({ mode: "snapshot" }));
|
|
43
45
|
return new Response(await this.handleSnapshot().text(), {
|
|
44
46
|
status: 201,
|
|
45
47
|
headers: { "content-type": "application/json" }
|
|
@@ -48,24 +50,9 @@ var InMemoryMengineServer = class {
|
|
|
48
50
|
dsl.dispose();
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
|
-
if (path === "draft" && method === "GET")
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const dsl = new MedeoDsl(this.doc);
|
|
55
|
-
try {
|
|
56
|
-
return Response.json({
|
|
57
|
-
...toVideoDraft(dsl.getSnapshot()),
|
|
58
|
-
version: this.version()
|
|
59
|
-
});
|
|
60
|
-
} catch (error) {
|
|
61
|
-
return Response.json({ error: {
|
|
62
|
-
code: "projection_unsupported",
|
|
63
|
-
message: String(error)
|
|
64
|
-
} }, { status: 422 });
|
|
65
|
-
} finally {
|
|
66
|
-
dsl.dispose();
|
|
67
|
-
}
|
|
68
|
-
}
|
|
53
|
+
if (path === "draft" && method === "GET") return this.handleDraft();
|
|
54
|
+
const revision = /^revisions\/(\d+)\/draft$/.exec(path);
|
|
55
|
+
if (revision && method === "GET") return this.handleDraft(Number(revision[1]));
|
|
69
56
|
if (/^\/internal\/mengine\/v1\/docs\/[^/]+\/bootstrap$/.test(new URL(url).pathname) && method === "POST") return this.handleBootstrap(init);
|
|
70
57
|
if (path.startsWith("sync") && method === "GET") return this.handleSync(url);
|
|
71
58
|
if (path === "updates" && method === "POST") return this.handlePush(init);
|
|
@@ -82,13 +69,37 @@ var InMemoryMengineServer = class {
|
|
|
82
69
|
const afterDocId = url.slice(start + 21);
|
|
83
70
|
return afterDocId.slice(afterDocId.indexOf("/") + 1);
|
|
84
71
|
}
|
|
85
|
-
version() {
|
|
72
|
+
version(doc = this.doc, seq = this.seq) {
|
|
86
73
|
return {
|
|
87
|
-
update_seq:
|
|
88
|
-
server_vv: bytesToBase64(
|
|
89
|
-
frontiers: bytesToBase64(encodeFrontiers(
|
|
74
|
+
update_seq: seq,
|
|
75
|
+
server_vv: bytesToBase64(doc.oplogVersion().encode()),
|
|
76
|
+
frontiers: bytesToBase64(encodeFrontiers(doc.oplogFrontiers()))
|
|
90
77
|
};
|
|
91
78
|
}
|
|
79
|
+
handleDraft(updateSeq) {
|
|
80
|
+
if (!this.hasSnapshot) return this.handleSnapshot();
|
|
81
|
+
const seq = updateSeq ?? this.seq;
|
|
82
|
+
const snapshot = this.revisions.get(seq);
|
|
83
|
+
if (!snapshot) return Response.json({ code: "not_found" }, { status: 404 });
|
|
84
|
+
const doc = new LoroDoc();
|
|
85
|
+
doc.import(snapshot);
|
|
86
|
+
const dsl = new MedeoDsl(doc);
|
|
87
|
+
try {
|
|
88
|
+
assertDslDocument(doc);
|
|
89
|
+
return Response.json({
|
|
90
|
+
...toVideoDraft(dsl.getSnapshot()),
|
|
91
|
+
version: this.version(doc, seq)
|
|
92
|
+
});
|
|
93
|
+
} catch (error) {
|
|
94
|
+
return Response.json({
|
|
95
|
+
code: updateSeq === void 0 ? "projection_unsupported" : "revision_unprojectable",
|
|
96
|
+
message: String(error)
|
|
97
|
+
}, { status: 422 });
|
|
98
|
+
} finally {
|
|
99
|
+
dsl.dispose();
|
|
100
|
+
doc.free();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
92
103
|
handleSnapshot() {
|
|
93
104
|
if (!this.hasSnapshot) return Response.json({
|
|
94
105
|
kind: "rejected",
|
|
@@ -105,6 +116,7 @@ var InMemoryMengineServer = class {
|
|
|
105
116
|
if (body.snapshot != null && !this.hasSnapshot) {
|
|
106
117
|
this.doc.import(base64ToBytes(body.snapshot));
|
|
107
118
|
this.hasSnapshot = true;
|
|
119
|
+
this.revisions.set(0, this.doc.export({ mode: "snapshot" }));
|
|
108
120
|
}
|
|
109
121
|
return this.handleSnapshot();
|
|
110
122
|
}
|
|
@@ -167,10 +179,16 @@ var InMemoryMengineServer = class {
|
|
|
167
179
|
try {
|
|
168
180
|
probe.import(this.doc.export({ mode: "snapshot" }));
|
|
169
181
|
probe.import(data);
|
|
170
|
-
|
|
182
|
+
let unsupported = documentFormat(probe) === "mixed";
|
|
183
|
+
if (documentFormat(probe) === "dsl") try {
|
|
184
|
+
assertPhoneticBindingFormat(probe);
|
|
185
|
+
} catch {
|
|
186
|
+
unsupported = true;
|
|
187
|
+
}
|
|
188
|
+
if (unsupported) return Response.json({
|
|
171
189
|
kind: "rejected",
|
|
172
190
|
code: "unsupported_document_format",
|
|
173
|
-
message: "
|
|
191
|
+
message: "Unsupported or mixed DSL storage format",
|
|
174
192
|
server_version: serverVersion
|
|
175
193
|
}, { status: 422 });
|
|
176
194
|
} finally {
|
|
@@ -179,6 +197,7 @@ var InMemoryMengineServer = class {
|
|
|
179
197
|
this.doc.import(data);
|
|
180
198
|
this.hasSnapshot = true;
|
|
181
199
|
this.seq += 1;
|
|
200
|
+
this.revisions.set(this.seq, this.doc.export({ mode: "snapshot" }));
|
|
182
201
|
const meta = extractMeta(this.doc, baseVV);
|
|
183
202
|
const stored = {
|
|
184
203
|
updateSeq: this.seq,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
|
-
import { Cursor } from "loro-crdt";
|
|
2
|
+
import { Cursor, isContainer } from "loro-crdt";
|
|
3
3
|
//#region ../medeo-dsl/src/ids.ts
|
|
4
4
|
function bytesToBase64url(bytes) {
|
|
5
5
|
let binary = "";
|
|
@@ -145,8 +145,12 @@ function assertCaptionContent(value) {
|
|
|
145
145
|
}
|
|
146
146
|
const phonemeFields = {
|
|
147
147
|
...selectionFields,
|
|
148
|
-
phonemeScript: optional$1(
|
|
148
|
+
phonemeScript: optional$1(nonempty)
|
|
149
149
|
};
|
|
150
|
+
/** D190: omitted pronunciation uses the selected source words; an authored pronunciation is never empty. */
|
|
151
|
+
function assertPhonemeScript(value) {
|
|
152
|
+
if (value !== void 0 && !nonempty(value)) throw new Error("phonemeScript must be nonempty when provided");
|
|
153
|
+
}
|
|
150
154
|
function assertPhoneme(value) {
|
|
151
155
|
if (!segmentSelection(phonemeFields)(value)) throw new Error("Invalid phoneme");
|
|
152
156
|
}
|
|
@@ -1375,6 +1379,30 @@ const phonemeCodec = codec((v) => {
|
|
|
1375
1379
|
assertPhoneme(value);
|
|
1376
1380
|
return value;
|
|
1377
1381
|
});
|
|
1382
|
+
/** A row-owned binding couples the selection, pronunciation and its immutable file in one LWW value. */
|
|
1383
|
+
const phoneticBindingCodec = codec((value) => {
|
|
1384
|
+
assertEntity("phonetic-script-entities", value);
|
|
1385
|
+
assertPhoneticScript(void 0, { ...value });
|
|
1386
|
+
return JSON.stringify({
|
|
1387
|
+
phoneme: JSON.parse(phonemeCodec.encode(value.phoneme)),
|
|
1388
|
+
system: value.system,
|
|
1389
|
+
key: value.key,
|
|
1390
|
+
storageKey: value.storageKey,
|
|
1391
|
+
digest: value.digest
|
|
1392
|
+
});
|
|
1393
|
+
}, (raw) => {
|
|
1394
|
+
const value = JSON.parse(raw);
|
|
1395
|
+
if (!isRecord(value)) throw new Error("Expected a PhoneticScript binding");
|
|
1396
|
+
const phoneme = phonemeCodec.decode(JSON.stringify(value.phoneme));
|
|
1397
|
+
if (isInvalidAtomic(phoneme)) throw new Error(phoneme.reason);
|
|
1398
|
+
const binding = {
|
|
1399
|
+
...value,
|
|
1400
|
+
phoneme
|
|
1401
|
+
};
|
|
1402
|
+
assertEntity("phonetic-script-entities", binding);
|
|
1403
|
+
assertPhoneticScript(void 0, binding);
|
|
1404
|
+
return binding;
|
|
1405
|
+
});
|
|
1378
1406
|
/** A Clip's sequence marker is stored as one string, so it is taken or replaced whole. */
|
|
1379
1407
|
const seqMarkerCodec = codec((v) => {
|
|
1380
1408
|
assertSeqMarker(v);
|
|
@@ -1441,13 +1469,7 @@ const medeoDslLoroShape = schema({
|
|
|
1441
1469
|
storageKey: schema.String(optional),
|
|
1442
1470
|
digest: schema.String(optional)
|
|
1443
1471
|
})),
|
|
1444
|
-
"phonetic-script-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
1445
|
-
phoneme: atomicValue(phonemeCodec),
|
|
1446
|
-
system: schema.String(optional),
|
|
1447
|
-
key: schema.String(optional),
|
|
1448
|
-
storageKey: schema.String(optional),
|
|
1449
|
-
digest: schema.String(optional)
|
|
1450
|
-
})),
|
|
1472
|
+
"phonetic-script-entities": schema.LoroMapRecord(schema.LoroMap({ binding: atomicValue(phoneticBindingCodec) })),
|
|
1451
1473
|
"caption-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
1452
1474
|
selection: optionalAtomicValue(captionContentCodec),
|
|
1453
1475
|
text: schema.LoroText(optional),
|
|
@@ -1499,14 +1521,24 @@ function documentFormat(doc) {
|
|
|
1499
1521
|
}
|
|
1500
1522
|
var UnsupportedDocumentFormatError = class extends Error {
|
|
1501
1523
|
code = "unsupported_document_format";
|
|
1502
|
-
constructor() {
|
|
1503
|
-
super(
|
|
1524
|
+
constructor(message = "Expected a new DSL document; legacy, mixed or uninitialized content is not supported") {
|
|
1525
|
+
super(message);
|
|
1504
1526
|
this.name = "UnsupportedDocumentFormatError";
|
|
1505
1527
|
}
|
|
1506
1528
|
};
|
|
1507
1529
|
/** Run after initial import, before opening an editable handle. Empty new documents still have one Timeline. */
|
|
1508
1530
|
function assertDslDocument(doc) {
|
|
1509
1531
|
if (documentFormat(doc) !== "dsl" || doc.getMap("timeline-entities").keys().length !== 1) throw new UnsupportedDocumentFormatError();
|
|
1532
|
+
assertPhoneticBindingFormat(doc);
|
|
1533
|
+
}
|
|
1534
|
+
/** This storage cutover has no field-per-fact reader or mixed-version write path. */
|
|
1535
|
+
function assertPhoneticBindingFormat(doc) {
|
|
1536
|
+
if (!Object.hasOwn(doc.getShallowValue(), "phonetic-script-entities")) return;
|
|
1537
|
+
const table = doc.getMap("phonetic-script-entities");
|
|
1538
|
+
for (const id of table.keys()) {
|
|
1539
|
+
const row = table.get(id);
|
|
1540
|
+
if (!isContainer(row) || row.kind() !== "Map" || row.keys().some((key) => key !== "binding") || typeof row.get("binding") !== "string") throw new UnsupportedDocumentFormatError("PhoneticScript storage requires one atomic binding; old DSL documents need explicit migration");
|
|
1541
|
+
}
|
|
1510
1542
|
}
|
|
1511
1543
|
//#endregion
|
|
1512
1544
|
//#region ../medeo-dsl/src/schema/text-styles.ts
|
|
@@ -1516,4 +1548,4 @@ const textStyles = { language: { expand: "after" } };
|
|
|
1516
1548
|
//#region src/dsl/projection/video-draft-types.ts
|
|
1517
1549
|
const DEFAULT_UNIT_TIME_MS = 33.333;
|
|
1518
1550
|
//#endregion
|
|
1519
|
-
export {
|
|
1551
|
+
export { assertCaptionContent as $, deepEqual as A, isStateAndSchemaOfType as B, validateSchema as C, cidsEqual as D, applySchemaToInferOptions as E, inferContainerTypeFromValue as F, stripUndefined as G, isValueOfContainerType as H, insertChildToMap as I, valuesEqual as J, tryInferContainerType as K, isArrayLike as L, getRootContainerByType as M, hardenCidDescriptors as N, containerIdToContainerType as O, hasTransform as P, getMapFieldSchema as Q, isObject as R, schemaContainsIgnoreField as S, tupleHash as St, applyEncode as T, safeStringify as U, isTreeID as V, schemaToContainerType as W, getChildContainerSchema as X, CID_KEY as Y, getChildSchema as Z, isLoroListSchema as _, assertRelationIdentity as _t, assertPhoneticBindingFormat as a, assertPhoneticScript as at, isLoroTreeSchema as b, relationId as bt, captionContentCodec as c, assertSeqMarker as ct, phoneticBindingCodec as d, entityTables as dt, assertEntity as et, timeAnchorCodec as f, isRecord as ft, isListLikeSchema as g, validLanguage as gt, isContainerSchema as h, relationTables as ht, assertDslDocument as i, assertPhonemeScript as it, defineCidProperty as j, decodeNestedJsonValues as k, isInvalidAtomic as l, assertTimeAnchor as lt, getDefaultValue as m, patchRow as mt, textStyles as n, assertId as nt, documentFormat as o, assertRelation as ot, schema as p, mergeFields as pt, tryUpdateToContainer as q, UnsupportedDocumentFormatError as r, assertPhoneme as rt, medeoDslLoroShape as s, assertScriptSegment as st, DEFAULT_UNIT_TIME_MS as t, assertEntityPatch as tt, phonemeCodec as u, atomicFields as ut, isLoroMapSchema as v, assertResourceIdentity as vt, applyDecode as w, isRootSchemaType as x, resourceId as xt, isLoroMovableListSchema as y, defaultIdFactory as yt, isObjectLike as z };
|
|
@@ -879,4 +879,4 @@ type VideoDraftContent = Pick<VideoDraft, 'timeline' | 'main_track' | 'above_mai
|
|
|
879
879
|
type VideoDraftInput = Pick<VideoDraft, keyof VideoDraftContent>;
|
|
880
880
|
declare const DEFAULT_UNIT_TIME_MS = 33.333;
|
|
881
881
|
//#endregion
|
|
882
|
-
export {
|
|
882
|
+
export { TextMark as $, DeepReadonly as A, PhonemeSelection as B, CaptionContent as C, Clip as D, CaptionText as E, EntityTables as F, RelationValues as G, RelationMutation as H, EntityValues as I, SegmentRange as J, ResourceSystem as K, FieldPatch as L, DslMutation as M, EntityMutation as N, ContainMutation as O, EntityTable as P, TextEdit as Q, MedeoDslSnapshot as R, Caption as S, CaptionStyle$1 as T, RelationTable as U, PhoneticScript as V, RelationTables as W, StoredFile as X, SegmentSelection as Y, TextDelta as Z, defaultIdFactory as _, VideoDraftCaptionStyle as a, Voice as at, tupleHash as b, VideoDraftInput as c, VideoDraftTrack as d, TextMutation as et, VideoDraftTrackItem as f, EntityIdKind as g, DslIdFactory as h, VideoDraft as i, TrackRole as it, DslDiagnostic as j, ContainNode as k, VideoDraftPartUnion as l, OpActor as m, DEFAULT_UNIT_TIME_MS as n, TimeAnchor as nt, VideoDraftContent as o, CommitOptions as p, RichTextSnapshot as q, VideoCreationSettings as r, Track$1 as rt, VideoDraftContentPartUnion as s, CaptionDisplayCue as t, TextRun as tt, VideoDraftTimeline as u, relationId as v, CaptionSelection as w, AudioScript as x, resourceId as y, Media as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mengine/medeo-client",
|
|
3
|
-
"version": "2.1.1-dsl.
|
|
3
|
+
"version": "2.1.1-dsl.24",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"@noble/hashes": "^2.4.0",
|
|
30
30
|
"immer": "^10.2.0",
|
|
31
31
|
"zod": "^4.4.3",
|
|
32
|
-
"@mengine/storage": "2.1.1-dsl.
|
|
33
|
-
"@mengine/sync": "2.1.1-dsl.
|
|
34
|
-
"@mengine/utils": "2.1.1-dsl.
|
|
32
|
+
"@mengine/storage": "2.1.1-dsl.24",
|
|
33
|
+
"@mengine/sync": "2.1.1-dsl.24",
|
|
34
|
+
"@mengine/utils": "2.1.1-dsl.24"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^25.9.1",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"typescript": "^6.0.3",
|
|
43
43
|
"vite-plugin-wasm": "^3.6.0",
|
|
44
44
|
"vite-plus": "^0.1.23",
|
|
45
|
-
"@mengine/
|
|
46
|
-
"@mengine/
|
|
45
|
+
"@mengine/medeo-dsl": "0.0.0",
|
|
46
|
+
"@mengine/idl-codegen": "0.0.0"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"loro-crdt": "^1.16.1"
|