@mengine/medeo-client 2.0.1-alpha.2 → 2.0.1-alpha.21
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 +31 -0
- package/dist/{document-BSAUud6c.js → document-BXQcpnOg.js} +576 -332
- package/dist/{index-B31KeDzA.d.ts → index-CzDNr1Tb.d.ts} +297 -184
- package/dist/index.d.ts +594 -320
- package/dist/index.js +2221 -370
- 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 -19
- package/package.json +9 -9
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as index_d_exports } from "./index-CMa6ZCtX.js";
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as DerivedItemPosition, A as assertValidVideoDocument, At as VideoDocument, B as EntityRelationRows, Bt as CaptionStyle, C as isImplementedSemanticOpKind, Ct as SpeechOriginAssetSystem, D as PartIdFactory, Dt as TrackItem, E as ValidationError, Et as Track, F as ResolvedEntityTrack, Ft as VideoDraftPartUnion, G as ScriptTextSegment, Gt as TrackItem$1, H as RelationRow, Ht as SpeedShift, I as resolveEntityTimelineLayout, It as effectiveVideoClipDurationMs, J as VoiceDescriptor, K as SequenceDuration, L as EntityTimelineProjectionDocument, Lt as speedOf, M as EntityTimelineTrackRole, Mt as VideoDocumentValidationIssueCode, N as ResolvedEntityClipPlacement, Nt as VideoDraft, O as generatePartId, Ot as TrackItemTimePosition, P as ResolvedEntityTimelineLayout, Pt as VideoDraftContent, Q as buildInitialVideoDocument, R as projectEntityTimeline, Rt as Attachment, S as SemanticOpKind, St as PartUnion, T as SnapshotReadable, Tt as Timeline, U as CaptionSegmentSelection, Ut as Timeline$1, V as EntityRow, Vt as PartAggregation, W as CaptionStyleFields, Wt as Track$1, X as JsonValue, Y as JsonObject, Z as EntityId, _ as SemanticOpName, _t as BgmPart, a as PlainMemoryAdapter, at as LANE_KINDS_IN_STACK_ORDER, b as ImplementedSemanticOpKind, bt as DEFAULT_UNIT_TIME_MS, c as MirrorVideoDocumentAdapter, ct as ensureLaneTrack, d as createMirrorVideoDocumentAdapter, dt as solveVideoDocument, et as SpeechHostMap, f as CommitOptions, ft as TrackDraft, g as SemanticOpInput, gt as videoDocumentMirrorSchema, h as SemanticEditor, ht as VideoDocumentMirrorSchema, i as JournalEntry, it as toVideoDocument, j as validateVideoDocument, jt as VideoDocumentValidationIssue, k as VideoDocumentValidationError, kt as VideoClipPart, l as MirrorVideoDocumentOptions, lt as findLaneTrack, m as SemanticDocumentAdapter, mt as VideoDocumentDraft, n as videoDocumentSchema, nt as derivePositionFromAbs, o as PlainMemoryAdapterOptions, ot as LaneKind, p as OpActor, pt as TrackItemDraft, q as SequenceRange, r as readVideoDocumentFromDraft, rt as fromVideoDocument, s as createPlainMemoryAdapter, st as SolvedVideoDocument, t as partUnionSchema, tt as buildSpeechHostMap, u as createMirrorVideoDocument, ut as laneTrackId, v as TransactAudit, vt as CaptionDisplayCue, w as SchemaValidator, wt as SpeechPart, x as PlannedSemanticOpKind, xt as PartKind, y as IMPLEMENTED_SEMANTIC_OP_KINDS, yt as CaptionPart, z as EntityTimelineProjectionError, zt as CaptionPart$1 } from "./index-CzDNr1Tb.js";
|
|
3
3
|
import { LoroDoc, PeerID } from "loro-crdt";
|
|
4
4
|
import { DocState } from "@mengine/sync";
|
|
5
5
|
import { BaseDocStorage, Connection, DocDiff, DocPushReceipt, DocSnapshotRecord, DocStorage, DocStorageOptions, DocUpdate, DocUpdateRecord } from "@mengine/storage";
|
|
@@ -134,7 +134,6 @@ declare class MengineHttpClient {
|
|
|
134
134
|
private readonly fetchImpl;
|
|
135
135
|
constructor(options: MengineHttpClientOptions);
|
|
136
136
|
fetchSnapshot(): Promise<MengineSnapshotResponse>;
|
|
137
|
-
bootstrapSnapshot(snapshot: Uint8Array): Promise<MengineSnapshotResponse>;
|
|
138
137
|
/**
|
|
139
138
|
* Loro VV-diff pull: send the caller's oplog `VersionVector.encode` as `from`
|
|
140
139
|
* (omit for a full pull) and receive exactly the updates it is missing plus
|
|
@@ -175,6 +174,8 @@ interface MengineEventStreamOptions {
|
|
|
175
174
|
/** Fired once the stream response is established (HTTP ok, body readable). */
|
|
176
175
|
onOpen?(): void;
|
|
177
176
|
onUpdate(event: MengineSseUpdateEvent): void;
|
|
177
|
+
/** A committed update omitted from live transport; fetch the missing operations by VV. */
|
|
178
|
+
onResync?(): void;
|
|
178
179
|
}
|
|
179
180
|
declare function readMengineEventStream(options: MengineEventStreamOptions): Promise<void>;
|
|
180
181
|
//#endregion
|
|
@@ -191,6 +192,16 @@ interface AssembledCaptionContent {
|
|
|
191
192
|
readonly audioScript: EntityRow<'audio-script'>;
|
|
192
193
|
/** Selected AudioScript segments in Caption selection order. */
|
|
193
194
|
readonly segments: readonly ScriptTextSegment[];
|
|
195
|
+
/**
|
|
196
|
+
* Where the selected segment sits in the AudioScript's ordered segments.
|
|
197
|
+
*
|
|
198
|
+
* A Caption locates its text as AudioScript plus index. The selection is
|
|
199
|
+
* stored as the segment's own stable id rather than this ordinal, so a
|
|
200
|
+
* concurrent insert or re-segmentation cannot silently slide a Caption onto
|
|
201
|
+
* different text; the ordinal is derived here for readers that want the
|
|
202
|
+
* position.
|
|
203
|
+
*/
|
|
204
|
+
readonly segmentIndex: number;
|
|
194
205
|
/** Complete display text: the selected segments' text joined in order. */
|
|
195
206
|
readonly text: string;
|
|
196
207
|
}
|
|
@@ -221,8 +232,8 @@ declare function selectAudioScriptSegment(script: EntityRow<'audio-script'>, sel
|
|
|
221
232
|
//#region src/entity-editor/entity-graph-http-client.d.ts
|
|
222
233
|
/** One authenticated revision of the authoritative Medeo Entity graph. */
|
|
223
234
|
interface EntityGraphState {
|
|
224
|
-
/** Current AudioScript
|
|
225
|
-
readonly audioScriptEntityId: string;
|
|
235
|
+
/** Current AudioScript attached to the project, or null until one is written. */
|
|
236
|
+
readonly audioScriptEntityId: string | null;
|
|
226
237
|
readonly revision: number;
|
|
227
238
|
readonly loroSnapshot: string;
|
|
228
239
|
readonly rows: EntityRelationRows;
|
|
@@ -251,6 +262,171 @@ declare class EntityGraphHttpClient {
|
|
|
251
262
|
private request;
|
|
252
263
|
}
|
|
253
264
|
//#endregion
|
|
265
|
+
//#region src/entity-crdt/field-changes.d.ts
|
|
266
|
+
/** List members are addressed by identity, never a transient array offset. */
|
|
267
|
+
type FieldPath = readonly (string | {
|
|
268
|
+
elementId: string;
|
|
269
|
+
})[];
|
|
270
|
+
type FieldChange = {
|
|
271
|
+
op: 'set';
|
|
272
|
+
path: FieldPath;
|
|
273
|
+
value: JsonValue;
|
|
274
|
+
} | {
|
|
275
|
+
op: 'unset';
|
|
276
|
+
path: FieldPath;
|
|
277
|
+
} | {
|
|
278
|
+
op: 'text.splice';
|
|
279
|
+
path: FieldPath;
|
|
280
|
+
index: number;
|
|
281
|
+
deleteCount: number;
|
|
282
|
+
text: string;
|
|
283
|
+
} | {
|
|
284
|
+
op: 'list.insert';
|
|
285
|
+
path: FieldPath;
|
|
286
|
+
value: JsonValue;
|
|
287
|
+
beforeElementId: string | null;
|
|
288
|
+
} | {
|
|
289
|
+
op: 'list.move';
|
|
290
|
+
path: FieldPath;
|
|
291
|
+
elementId: string;
|
|
292
|
+
beforeElementId: string | null;
|
|
293
|
+
} | {
|
|
294
|
+
op: 'list.remove';
|
|
295
|
+
path: FieldPath;
|
|
296
|
+
elementId: string;
|
|
297
|
+
};
|
|
298
|
+
declare function assertFieldChanges(changes: readonly FieldChange[]): void;
|
|
299
|
+
/** Resolve against the sequential causal view; the numeric path never crosses the API boundary. */
|
|
300
|
+
declare function resolveFieldPath(payload: JsonObject, path: FieldPath): (string | number)[];
|
|
301
|
+
/** Detached plan evaluation. Native compilation replays the original operations, not this snapshot. */
|
|
302
|
+
declare function applyFieldChanges(payload: JsonObject, changes: readonly FieldChange[]): JsonObject;
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/entity-crdt/entity-document.d.ts
|
|
305
|
+
declare const LORO_ENTITY_SCHEMA = "medeo.entities.loro.v1";
|
|
306
|
+
interface EntityDocumentState {
|
|
307
|
+
readonly rows: EntityRelationRows;
|
|
308
|
+
readonly project: Readonly<Record<string, string>>;
|
|
309
|
+
}
|
|
310
|
+
type Command = {
|
|
311
|
+
type: 'create';
|
|
312
|
+
row: EntityRow;
|
|
313
|
+
} | {
|
|
314
|
+
type: 'selection-baseline';
|
|
315
|
+
root: string;
|
|
316
|
+
fingerprint: string;
|
|
317
|
+
} | {
|
|
318
|
+
type: 'order';
|
|
319
|
+
group: string;
|
|
320
|
+
roots: string[];
|
|
321
|
+
token: string;
|
|
322
|
+
} | {
|
|
323
|
+
type: 'write';
|
|
324
|
+
root: string;
|
|
325
|
+
payload: JsonObject;
|
|
326
|
+
token: string;
|
|
327
|
+
} | {
|
|
328
|
+
type: 'text';
|
|
329
|
+
root: string;
|
|
330
|
+
path: readonly (string | number)[];
|
|
331
|
+
start: number;
|
|
332
|
+
deleteCount: number;
|
|
333
|
+
text: string;
|
|
334
|
+
token: string;
|
|
335
|
+
} | {
|
|
336
|
+
type: 'field';
|
|
337
|
+
root: string;
|
|
338
|
+
path: (string | number)[];
|
|
339
|
+
change: FieldChange;
|
|
340
|
+
token: string;
|
|
341
|
+
} | {
|
|
342
|
+
type: 'relation-field';
|
|
343
|
+
root: string;
|
|
344
|
+
path: (string | number)[];
|
|
345
|
+
change: FieldChange;
|
|
346
|
+
} | {
|
|
347
|
+
type: 'delete';
|
|
348
|
+
root: string;
|
|
349
|
+
} | {
|
|
350
|
+
type: 'relation';
|
|
351
|
+
row: RelationRow;
|
|
352
|
+
} | {
|
|
353
|
+
type: 'relation-fields';
|
|
354
|
+
root: string;
|
|
355
|
+
metadata: JsonObject;
|
|
356
|
+
trace: JsonObject;
|
|
357
|
+
} | {
|
|
358
|
+
type: 'unlink';
|
|
359
|
+
root: string;
|
|
360
|
+
} | {
|
|
361
|
+
type: 'attach';
|
|
362
|
+
slot: string;
|
|
363
|
+
entityId: string;
|
|
364
|
+
};
|
|
365
|
+
/** Plain domain objects assembled from native Loro state, never a second writable authority. */
|
|
366
|
+
declare function readEntityDocument(doc: LoroDoc, allowSelectionConflicts?: boolean): EntityDocumentState;
|
|
367
|
+
/** Native editing containers survive domain version changes and merge independently. */
|
|
368
|
+
declare class LoroEntityDocument {
|
|
369
|
+
readonly doc: LoroDoc;
|
|
370
|
+
private readonly validate?;
|
|
371
|
+
private readonly undoManager;
|
|
372
|
+
constructor(doc: LoroDoc, validate?: ((state: EntityDocumentState) => void) | undefined);
|
|
373
|
+
/** Open a causal snapshot using the same Loro runtime as the compiler. */
|
|
374
|
+
static fromSnapshot(snapshot: Uint8Array, validate?: (state: EntityDocumentState) => void): LoroEntityDocument;
|
|
375
|
+
static create(rows: EntityRelationRows, project?: Readonly<Record<string, string>>, peerId?: PeerID): LoroEntityDocument;
|
|
376
|
+
snapshot(): EntityDocumentState;
|
|
377
|
+
relationsOf(entityId: string): readonly RelationRow[];
|
|
378
|
+
/** Read unlinked Relation records for durable effect receipts; never part of the current semantic graph. */
|
|
379
|
+
tombstonedRelations(): readonly RelationRow[];
|
|
380
|
+
/** Resolve a queued edit target through its native identity without changing history. */
|
|
381
|
+
resolveCurrentEntityId(id: string): string;
|
|
382
|
+
getVersion(id: string): EntityRow | undefined;
|
|
383
|
+
/** The callback and every domain validation execute on a causally complete fork first. */
|
|
384
|
+
transact(edit: (draft: LoroEntityDraft) => void): Uint8Array;
|
|
385
|
+
/** Import preserves native operation identities; projection errors never discard remote operations. */
|
|
386
|
+
import(update: Uint8Array): void;
|
|
387
|
+
/**
|
|
388
|
+
* Bind a saved snapshot without rewriting text operations or resolving
|
|
389
|
+
* selection conflicts. The script names the bytes the same way everything
|
|
390
|
+
* else does — an Asset entity plus a Relation — and keeps only the
|
|
391
|
+
* fingerprint that tells a stale snapshot from a current one. The Relation is
|
|
392
|
+
* `to-asset`: these bytes are the script's own content written out, not a
|
|
393
|
+
* source it was made from.
|
|
394
|
+
*/
|
|
395
|
+
bindAudioScriptAsset(entityId: string, assetId: string, expectedContentHash: string): Uint8Array;
|
|
396
|
+
canUndo(): boolean;
|
|
397
|
+
canRedo(): boolean;
|
|
398
|
+
undo(): boolean;
|
|
399
|
+
redo(): boolean;
|
|
400
|
+
private historyEdit;
|
|
401
|
+
}
|
|
402
|
+
declare class LoroEntityDraft {
|
|
403
|
+
private readonly doc;
|
|
404
|
+
readonly commands: Command[];
|
|
405
|
+
private readonly selectedRoots;
|
|
406
|
+
private readonly relationAliases;
|
|
407
|
+
constructor(doc: LoroDoc);
|
|
408
|
+
snapshot(): EntityDocumentState;
|
|
409
|
+
order(groupId: string, entityIds: readonly string[]): void;
|
|
410
|
+
/** Project the final scalar placement intents onto the existing native ordering containers. */
|
|
411
|
+
reconcileOrder(rows: EntityRelationRows): void;
|
|
412
|
+
create(row: EntityRow): void;
|
|
413
|
+
delete(entityId: string): void;
|
|
414
|
+
attach(slot: string, entityId: string): void;
|
|
415
|
+
link(row: RelationRow): void;
|
|
416
|
+
patchRelation(relationId: string, metadata: JsonObject, trace: JsonObject): void;
|
|
417
|
+
unlink(relationId: string): void;
|
|
418
|
+
private relationRoot;
|
|
419
|
+
update(entityId: string, fields: JsonObject): void;
|
|
420
|
+
declare(entityId: string, fields: JsonObject): void;
|
|
421
|
+
replaceOwned(entityId: string, payload: JsonObject): void;
|
|
422
|
+
editText(entityId: string, path: readonly (string | number)[], start: number, deleteCount: number, text: string): void;
|
|
423
|
+
/** Generic assembled-field edit compiled at the author's causal position. */
|
|
424
|
+
change(entityId: string, changes: readonly FieldChange[]): void;
|
|
425
|
+
changeRelation(relationId: string, changes: readonly FieldChange[]): void;
|
|
426
|
+
captureSelectionBaselines(): void;
|
|
427
|
+
private record;
|
|
428
|
+
}
|
|
429
|
+
//#endregion
|
|
254
430
|
//#region src/entity-editor/types.d.ts
|
|
255
431
|
/** Injectable domain-id mint shared by Entity and Relation authoring surfaces. */
|
|
256
432
|
type EntityTimelineIdFactory = (prefix: 'entity' | 'relation') => string;
|
|
@@ -271,17 +447,94 @@ interface AudioMediaAssetFact {
|
|
|
271
447
|
readonly durationMs: number;
|
|
272
448
|
readonly storageKey: string;
|
|
273
449
|
}
|
|
274
|
-
|
|
450
|
+
/**
|
|
451
|
+
* Speech. It materializes as a `voiceover` entity — its own kind, because only
|
|
452
|
+
* speech answers which words it said; `voice` names the timbre identity it was
|
|
453
|
+
* synthesized with, which becomes its own Voice entity linked by a
|
|
454
|
+
* `voice-timbre` Relation.
|
|
455
|
+
*/
|
|
456
|
+
interface VoiceoverMediaAssetFact {
|
|
275
457
|
/** Stable external speech result id, independent of the placed Clip id. */
|
|
276
458
|
readonly assetId: string;
|
|
277
|
-
readonly kind: '
|
|
459
|
+
readonly kind: 'voiceover';
|
|
278
460
|
readonly durationMs: number;
|
|
279
461
|
readonly storageKey: string;
|
|
280
|
-
/**
|
|
462
|
+
/**
|
|
463
|
+
* The PhoneticScript this take was spoken from, when the caller minting it
|
|
464
|
+
* knows. A migration that rebuilds the whole chain relates it itself; either
|
|
465
|
+
* way a take that never names one is refused when a plan is built.
|
|
466
|
+
*/
|
|
467
|
+
readonly phoneticScriptEntityId?: string;
|
|
468
|
+
/** Present for synthesized speech, absent for original recorded audio. */
|
|
281
469
|
readonly voice?: VoiceDescriptor;
|
|
282
470
|
}
|
|
283
471
|
/** Facts resolved from media storage. A trim window never substitutes for intrinsic duration. */
|
|
284
|
-
type MediaAssetFact = ImageMediaAssetFact | VideoMediaAssetFact | AudioMediaAssetFact |
|
|
472
|
+
type MediaAssetFact = ImageMediaAssetFact | VideoMediaAssetFact | AudioMediaAssetFact | VoiceoverMediaAssetFact;
|
|
473
|
+
/** Host-resolved ASR artifact. The SDK treats its storage fields as opaque facts. */
|
|
474
|
+
interface CaptionAssetFact {
|
|
475
|
+
readonly assetId: string;
|
|
476
|
+
readonly storageKey?: string;
|
|
477
|
+
}
|
|
478
|
+
interface AsrCaptionSegment extends ScriptTextSegment {
|
|
479
|
+
readonly startMs: number;
|
|
480
|
+
readonly endMs: number;
|
|
481
|
+
}
|
|
482
|
+
/** One closed host command for materializing an ASR result into the Entity graph. */
|
|
483
|
+
interface ApplyCaptionAssetsInput {
|
|
484
|
+
readonly effectId: string;
|
|
485
|
+
readonly timelineEntityId: string;
|
|
486
|
+
readonly trackEntityId: string;
|
|
487
|
+
readonly source: {
|
|
488
|
+
readonly entityId: string;
|
|
489
|
+
readonly entityKind: 'audio' | 'video';
|
|
490
|
+
};
|
|
491
|
+
/** The exact placed use whose source-relative ASR timing is being materialized. */
|
|
492
|
+
readonly sourceOccurrence: {
|
|
493
|
+
readonly clipEntityId: string;
|
|
494
|
+
readonly markerEntityId: string;
|
|
495
|
+
};
|
|
496
|
+
readonly captionAsset: CaptionAssetFact;
|
|
497
|
+
readonly segments: readonly AsrCaptionSegment[];
|
|
498
|
+
}
|
|
499
|
+
interface ApplyCaptionAssetsResult {
|
|
500
|
+
readonly audioScriptEntityId: string;
|
|
501
|
+
readonly audioScriptMarkerEntityId: string;
|
|
502
|
+
readonly captionAssetEntityId: string;
|
|
503
|
+
readonly captionEntityIds: readonly string[];
|
|
504
|
+
readonly captionClipEntityIds: readonly string[];
|
|
505
|
+
}
|
|
506
|
+
interface CaptionAssetsEffectEnvelope {
|
|
507
|
+
readonly version: 1;
|
|
508
|
+
readonly baselineFingerprint: string;
|
|
509
|
+
readonly effectId: string;
|
|
510
|
+
readonly signature: string;
|
|
511
|
+
readonly input: ApplyCaptionAssetsInput;
|
|
512
|
+
readonly decisions: {
|
|
513
|
+
readonly sourceOccurrence: {
|
|
514
|
+
readonly sourceStartMs: number;
|
|
515
|
+
readonly sourceEndMs: number;
|
|
516
|
+
readonly timelineStartMs: number;
|
|
517
|
+
readonly rate: number;
|
|
518
|
+
};
|
|
519
|
+
readonly targetRanges: readonly {
|
|
520
|
+
readonly segmentId: string;
|
|
521
|
+
readonly start: number;
|
|
522
|
+
readonly end: number;
|
|
523
|
+
}[];
|
|
524
|
+
readonly captionAsset: {
|
|
525
|
+
readonly mode: 'create' | 'reuse' | 'replace';
|
|
526
|
+
readonly priorAssetEntityId?: string;
|
|
527
|
+
readonly resultAssetEntityId: string;
|
|
528
|
+
readonly reboundRelationIds: readonly string[];
|
|
529
|
+
};
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
interface CompiledCaptionAssetsEffect {
|
|
533
|
+
readonly result: ApplyCaptionAssetsResult;
|
|
534
|
+
readonly replayed: boolean;
|
|
535
|
+
readonly update?: Uint8Array;
|
|
536
|
+
readonly rows: EntityRelationRows;
|
|
537
|
+
}
|
|
285
538
|
type ClipPlacement = {
|
|
286
539
|
readonly kind: 'sequential';
|
|
287
540
|
readonly order: number;
|
|
@@ -333,7 +586,7 @@ interface DeleteClipTreeInput {
|
|
|
333
586
|
interface VoiceoverCaptionFact {
|
|
334
587
|
/** Stable placed caption identity supplied by the materialized side effect. */
|
|
335
588
|
readonly captionClipEntityId: string;
|
|
336
|
-
/** Directly held bases; includes the AudioScript
|
|
589
|
+
/** Directly held bases; includes the AudioScript the voiceover was rendered from. */
|
|
337
590
|
readonly baseEntityIds: readonly string[];
|
|
338
591
|
/** Ordered selection of AudioScript segments; caption text is never passed inline. */
|
|
339
592
|
readonly selection: CaptionSegmentSelection;
|
|
@@ -344,7 +597,7 @@ interface VoiceoverCaptionFact {
|
|
|
344
597
|
type VoiceoverTakeInput = {
|
|
345
598
|
readonly timelineEntityId: string; /** Stable placed speech identity, distinct from media.assetId. */
|
|
346
599
|
readonly voiceoverClipEntityId: string;
|
|
347
|
-
readonly media:
|
|
600
|
+
readonly media: VoiceoverMediaAssetFact; /** Existing pronunciation variant; its composed AudioScript stays the text owner. */
|
|
348
601
|
readonly phoneticScriptEntityId: string;
|
|
349
602
|
readonly volume: number;
|
|
350
603
|
readonly captions: readonly VoiceoverCaptionFact[];
|
|
@@ -414,14 +667,168 @@ interface SetClipSpeedInput {
|
|
|
414
667
|
readonly clipEntityId: string;
|
|
415
668
|
readonly timeRemapping: LinearClipSpeed | null;
|
|
416
669
|
}
|
|
670
|
+
type VideoClipSpeedMode = '0.5x' | '0.75x' | '1.0x' | '1.5x' | '2.0x';
|
|
671
|
+
interface SetVideoClipSpeedEffectInput {
|
|
672
|
+
readonly clips: readonly {
|
|
673
|
+
readonly videoClipEntityId: string;
|
|
674
|
+
readonly mode: VideoClipSpeedMode;
|
|
675
|
+
}[];
|
|
676
|
+
}
|
|
677
|
+
interface GeneratedVisualClipFact {
|
|
678
|
+
readonly media: VisualMediaAssetFact;
|
|
679
|
+
/** Finite timeline use duration. Required for still images and bounded for video. */
|
|
680
|
+
readonly durationMs: number;
|
|
681
|
+
readonly generationJobId: string;
|
|
682
|
+
readonly sourceMediaEntityIds: readonly string[];
|
|
683
|
+
readonly volume?: number;
|
|
684
|
+
}
|
|
685
|
+
interface GeneratedVisualsInputBase {
|
|
686
|
+
readonly effectId: string;
|
|
687
|
+
readonly timelineEntityId: string;
|
|
688
|
+
readonly clips: readonly GeneratedVisualClipFact[];
|
|
689
|
+
}
|
|
690
|
+
/** An omitted occurrence anchor means the start of the main visual Track. */
|
|
691
|
+
type AddGeneratedVisualsInput = GeneratedVisualsInputBase & ({
|
|
692
|
+
readonly beforeClipEntityId: string;
|
|
693
|
+
readonly afterClipEntityId?: never;
|
|
694
|
+
} | {
|
|
695
|
+
readonly beforeClipEntityId?: never;
|
|
696
|
+
readonly afterClipEntityId: string;
|
|
697
|
+
} | {
|
|
698
|
+
readonly beforeClipEntityId?: never;
|
|
699
|
+
readonly afterClipEntityId?: never;
|
|
700
|
+
});
|
|
701
|
+
interface ContinueVideoInput {
|
|
702
|
+
readonly effectId: string;
|
|
703
|
+
readonly timelineEntityId: string;
|
|
704
|
+
readonly afterClipEntityId: string;
|
|
705
|
+
readonly tailFrameEntityId: string;
|
|
706
|
+
readonly sourceMediaEntityId: string;
|
|
707
|
+
readonly media: VideoMediaAssetFact;
|
|
708
|
+
}
|
|
709
|
+
interface GeneratedVisualEffectEnvelope {
|
|
710
|
+
readonly version: 1;
|
|
711
|
+
readonly baselineFingerprint: string;
|
|
712
|
+
readonly effectId: string;
|
|
713
|
+
readonly signature: string;
|
|
714
|
+
readonly input: AddGeneratedVisualsInput;
|
|
715
|
+
readonly decisions: {
|
|
716
|
+
readonly trackEntityId: string;
|
|
717
|
+
readonly anchorOrder: number | null;
|
|
718
|
+
readonly anchorPosition: 'before' | 'after' | 'track_start';
|
|
719
|
+
readonly insertionOrders: readonly number[];
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
interface GeneratedVisualEffectResult {
|
|
723
|
+
readonly clipEntityIds: readonly string[];
|
|
724
|
+
readonly mediaEntityIds: readonly string[];
|
|
725
|
+
}
|
|
726
|
+
interface CompiledGeneratedVisualEffect {
|
|
727
|
+
readonly result: GeneratedVisualEffectResult;
|
|
728
|
+
readonly replayed: boolean;
|
|
729
|
+
readonly update?: Uint8Array;
|
|
730
|
+
readonly rows: EntityRelationRows;
|
|
731
|
+
}
|
|
732
|
+
interface GeneratedSpeechCaptionFact {
|
|
733
|
+
readonly startMs: number;
|
|
734
|
+
readonly endMs: number;
|
|
735
|
+
readonly selection: CaptionSegmentSelection;
|
|
736
|
+
}
|
|
737
|
+
/** Host-resolved current Loro segment; arbitrary immutable JSON fields remain owned by the script. */
|
|
738
|
+
type ResolvedSpeechScriptSegment = ScriptTextSegment & JsonObject;
|
|
739
|
+
type ResolvedAsrSpeechSegment = AsrCaptionSegment & JsonObject;
|
|
740
|
+
type GeneratedSpeechSourceFact = {
|
|
741
|
+
readonly kind: 'phonetic-script';
|
|
742
|
+
readonly audioScriptEntityId: string;
|
|
743
|
+
readonly phoneticScriptEntityId: string;
|
|
744
|
+
readonly segments: readonly ResolvedSpeechScriptSegment[];
|
|
745
|
+
readonly phonemeScript?: string;
|
|
746
|
+
} | {
|
|
747
|
+
readonly kind: 'audio-script';
|
|
748
|
+
readonly audioScriptEntityId?: string;
|
|
749
|
+
readonly segments: readonly ResolvedAsrSpeechSegment[];
|
|
750
|
+
readonly sourceMediaEntityIds: readonly string[];
|
|
751
|
+
readonly sourceStartMs: number;
|
|
752
|
+
};
|
|
753
|
+
interface GeneratedSpeechFactBase {
|
|
754
|
+
readonly source: GeneratedSpeechSourceFact;
|
|
755
|
+
readonly captions: readonly GeneratedSpeechCaptionFact[];
|
|
756
|
+
readonly volume?: number;
|
|
757
|
+
}
|
|
758
|
+
type GeneratedSpeechFact = GeneratedSpeechFactBase & ({
|
|
759
|
+
readonly renderMode: 'recorded';
|
|
760
|
+
readonly media: AudioMediaAssetFact;
|
|
761
|
+
readonly source: Extract<GeneratedSpeechSourceFact, {
|
|
762
|
+
kind: 'audio-script';
|
|
763
|
+
}>;
|
|
764
|
+
} | {
|
|
765
|
+
readonly renderMode: 'synthesized';
|
|
766
|
+
readonly media: Omit<VoiceoverMediaAssetFact, 'voice'> & {
|
|
767
|
+
readonly voice: VoiceDescriptor;
|
|
768
|
+
};
|
|
769
|
+
});
|
|
770
|
+
interface AddSpeechAssetsInput {
|
|
771
|
+
readonly effectId: string;
|
|
772
|
+
readonly timelineEntityId: string;
|
|
773
|
+
readonly items: readonly (GeneratedSpeechFact & {
|
|
774
|
+
readonly placementStartMs: number;
|
|
775
|
+
})[];
|
|
776
|
+
}
|
|
777
|
+
interface ReplaceVoiceSpeechAssetsInput {
|
|
778
|
+
readonly effectId: string;
|
|
779
|
+
readonly timelineEntityId: string;
|
|
780
|
+
readonly items: readonly (Extract<GeneratedSpeechFact, {
|
|
781
|
+
renderMode: 'synthesized';
|
|
782
|
+
}> & {
|
|
783
|
+
readonly targetSpeechClipEntityId: string; /** Explicit current Caption uses replaced with this selected speech use. */
|
|
784
|
+
readonly targetCaptionClipEntityIds: readonly string[];
|
|
785
|
+
})[];
|
|
786
|
+
}
|
|
787
|
+
type SpeechAssetsEffectInput = {
|
|
788
|
+
readonly mode: 'add';
|
|
789
|
+
readonly value: AddSpeechAssetsInput;
|
|
790
|
+
} | {
|
|
791
|
+
readonly mode: 'replace-voice';
|
|
792
|
+
readonly value: ReplaceVoiceSpeechAssetsInput;
|
|
793
|
+
};
|
|
794
|
+
interface SpeechAssetsEffectEnvelope {
|
|
795
|
+
readonly version: 1;
|
|
796
|
+
readonly baselineFingerprint: string;
|
|
797
|
+
readonly effectId: string;
|
|
798
|
+
readonly signature: string;
|
|
799
|
+
readonly input: SpeechAssetsEffectInput;
|
|
800
|
+
readonly decisions: {
|
|
801
|
+
readonly speechTrackEntityId: string;
|
|
802
|
+
readonly captionTrackEntityId?: string;
|
|
803
|
+
readonly targetStartsMs: readonly number[]; /** Existing raw-Audio occurrences reused by recorded items; positional with input items. */
|
|
804
|
+
readonly recordedSpeechClipEntityIds: readonly (string | null)[];
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
interface SpeechAssetsEffectResult {
|
|
808
|
+
readonly speechClipEntityIds: readonly string[];
|
|
809
|
+
readonly speechAudioEntityIds: readonly string[];
|
|
810
|
+
readonly audioScriptEntityIds: readonly string[];
|
|
811
|
+
/** Positional per input item; recorded audio has no pronunciation variant. */
|
|
812
|
+
readonly phoneticScriptEntityIds: readonly (string | null)[];
|
|
813
|
+
readonly captionClipEntityIds: readonly (readonly string[])[];
|
|
814
|
+
}
|
|
815
|
+
interface CompiledSpeechAssetsEffect {
|
|
816
|
+
readonly result: SpeechAssetsEffectResult;
|
|
817
|
+
readonly replayed: boolean;
|
|
818
|
+
readonly update?: Uint8Array;
|
|
819
|
+
readonly rows: EntityRelationRows;
|
|
820
|
+
}
|
|
417
821
|
interface TrimClipInput {
|
|
418
822
|
readonly clipEntityId: string;
|
|
419
823
|
readonly sourceRange: SequenceRange<number>;
|
|
420
824
|
}
|
|
421
825
|
interface VoiceoverTakeResult {
|
|
422
826
|
readonly voiceoverClipEntityId: string;
|
|
423
|
-
|
|
424
|
-
|
|
827
|
+
/** The rendered voiceover Audio entity. */
|
|
828
|
+
readonly voiceoverAudioEntityId: string;
|
|
829
|
+
/** The timbre identity it was synthesized with, when the take declared one. */
|
|
830
|
+
readonly voiceEntityId?: string;
|
|
831
|
+
/** The pronunciation variant the voiceover was rendered from. */
|
|
425
832
|
readonly phoneticScriptEntityId: string;
|
|
426
833
|
/** The base-text owner resolved from the PhoneticScript baseEntityIds. */
|
|
427
834
|
readonly audioScriptEntityId: string;
|
|
@@ -516,6 +923,7 @@ type ClipEntityId = EntityId;
|
|
|
516
923
|
* and committed only after validation succeeds.
|
|
517
924
|
*/
|
|
518
925
|
declare class EntityTimelineEditor {
|
|
926
|
+
#private;
|
|
519
927
|
private readonly idFactory;
|
|
520
928
|
private state;
|
|
521
929
|
constructor(initialRows: EntityRelationRows, idFactory?: EntityTimelineIdFactory);
|
|
@@ -533,6 +941,9 @@ declare class EntityTimelineEditor {
|
|
|
533
941
|
replaceMediaClip(input: ReplaceMediaClipInput): void;
|
|
534
942
|
setClipVolume(input: SetClipVolumeInput): void;
|
|
535
943
|
setClipSpeed(input: SetClipSpeedInput): void;
|
|
944
|
+
/** Apply one typed Director speed effect as a single graph transaction. */
|
|
945
|
+
setVideoClipSpeeds(input: SetVideoClipSpeedEffectInput): void;
|
|
946
|
+
private setClipSpeedIntoDraft;
|
|
536
947
|
trimClip(input: TrimClipInput): void;
|
|
537
948
|
replaceSequentialClips(input: ReplaceSequentialClipsInput): readonly ClipEntityId[];
|
|
538
949
|
deleteClip(input: DeleteClipInput): void;
|
|
@@ -553,9 +964,12 @@ declare class EntityTimelineEditor {
|
|
|
553
964
|
* never the Caption entity or the AudioScript.
|
|
554
965
|
*/
|
|
555
966
|
insertCaptionClip(input: InsertCaptionClipInput): ClipEntityId;
|
|
967
|
+
static compileCaptionAssetsEffect(base: LoroEntityDocument, envelope: CaptionAssetsEffectEnvelope): CompiledCaptionAssetsEffect;
|
|
968
|
+
static compileGeneratedVisualEffect(base: LoroEntityDocument, envelope: GeneratedVisualEffectEnvelope): CompiledGeneratedVisualEffect;
|
|
969
|
+
static compileSpeechAssetsEffect(base: LoroEntityDocument, envelope: SpeechAssetsEffectEnvelope): CompiledSpeechAssetsEffect;
|
|
556
970
|
private insertPlacedClipIntoDraft;
|
|
557
971
|
private ensureRoleTrack;
|
|
558
|
-
/** The existing pronunciation variant a
|
|
972
|
+
/** The existing pronunciation variant a voiceover consumes; composition is required. */
|
|
559
973
|
private requireComposedPhoneticScript;
|
|
560
974
|
/** Preserve the factual synthesis input, regardless of persisted endpoint positions. */
|
|
561
975
|
private ensurePhoneticRender;
|
|
@@ -581,6 +995,21 @@ declare class EntityTimelineEditor {
|
|
|
581
995
|
private relinkRelation;
|
|
582
996
|
private mintRelationId;
|
|
583
997
|
}
|
|
998
|
+
/** Freeze every state-dependent choice once in the sole FE tool-effect handler. */
|
|
999
|
+
declare function prepareCaptionAssetsEffect(base: LoroEntityDocument, rawInput: ApplyCaptionAssetsInput): CaptionAssetsEffectEnvelope;
|
|
1000
|
+
/**
|
|
1001
|
+
* Compile only a frozen envelope on its exact causal baseline. Collaborators
|
|
1002
|
+
* receive the resulting Loro update, never the raw effect.
|
|
1003
|
+
*/
|
|
1004
|
+
declare function compileCaptionAssetsEffect(base: LoroEntityDocument, envelope: CaptionAssetsEffectEnvelope): CompiledCaptionAssetsEffect;
|
|
1005
|
+
/** Freeze the insertion position and lineage on one causal baseline. */
|
|
1006
|
+
declare function prepareGeneratedVisualEffect(base: LoroEntityDocument, rawInput: AddGeneratedVisualsInput): GeneratedVisualEffectEnvelope;
|
|
1007
|
+
declare function prepareContinueVideoEffect(base: LoroEntityDocument, input: ContinueVideoInput): GeneratedVisualEffectEnvelope;
|
|
1008
|
+
/** Compile once at the FE authority; retain the returned update bytes for retry and collaborators. */
|
|
1009
|
+
declare function compileGeneratedVisualEffect(base: LoroEntityDocument, envelope: GeneratedVisualEffectEnvelope): CompiledGeneratedVisualEffect;
|
|
1010
|
+
declare function prepareSpeechAssetsEffect(base: LoroEntityDocument, rawInput: SpeechAssetsEffectInput): SpeechAssetsEffectEnvelope;
|
|
1011
|
+
/** Compile once at the FE authority; retain the returned update bytes for retry and collaborators. */
|
|
1012
|
+
declare function compileSpeechAssetsEffect(base: LoroEntityDocument, envelope: SpeechAssetsEffectEnvelope): CompiledSpeechAssetsEffect;
|
|
584
1013
|
//#endregion
|
|
585
1014
|
//#region src/entity-editor/editor-resources.d.ts
|
|
586
1015
|
declare const roleOrder: {
|
|
@@ -595,32 +1024,29 @@ interface EditorFoundation {
|
|
|
595
1024
|
readonly timelineEntityId: string;
|
|
596
1025
|
readonly trackEntityIds: Readonly<Record<EditorTrackRole, string>>;
|
|
597
1026
|
/** Initial or current AudioScript content ID selected by the foundation. */
|
|
598
|
-
readonly audioScriptEntityId: string;
|
|
1027
|
+
readonly audioScriptEntityId: string | null;
|
|
599
1028
|
}
|
|
600
1029
|
/**
|
|
601
1030
|
* MEngine editor policy, not a cardinality restriction on the general-purpose DSL.
|
|
602
1031
|
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
* are rejected, not migrated. Caption composes AudioScript text and may associate with a physical text Asset.
|
|
1032
|
+
* Resources live on Asset entities and are reached through `from-asset`: no
|
|
1033
|
+
* other entity carries a locator, one Asset claims each `(system, key)` pair,
|
|
1034
|
+
* and media reaches at most one Asset. Media whose bytes are not named through
|
|
1035
|
+
* that Relation is rejected rather than guessed at.
|
|
608
1036
|
*/
|
|
609
1037
|
declare function assertCanonicalEditorResources(rows: EntityRelationRows): void;
|
|
610
1038
|
/**
|
|
611
1039
|
* Commit-transition policy shared by the editor, the HTTP commit boundary, the
|
|
612
1040
|
* host tool, and the entity stores. It compares the authoritative before and
|
|
613
|
-
* after rows of one CAS commit and enforces the
|
|
614
|
-
*
|
|
1041
|
+
* after rows of one CAS commit and enforces the resource rules on the complete
|
|
1042
|
+
* after state, with no exemption for historical graphs:
|
|
615
1043
|
*
|
|
616
|
-
* 1. every
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
* another asset id.
|
|
1044
|
+
* 1. every media Entity reaches exactly one Asset through `from-asset`;
|
|
1045
|
+
* 2. no entity other than an Asset carries a locator;
|
|
1046
|
+
* 3. an Asset's locator is immutable — pointing it at other bytes would
|
|
1047
|
+
* silently rewrite every entity already made from it.
|
|
621
1048
|
*
|
|
622
|
-
*
|
|
623
|
-
* implicitly. Deleting media is explicit and allowed.
|
|
1049
|
+
* Deleting media is explicit and allowed.
|
|
624
1050
|
*/
|
|
625
1051
|
declare function assertMediaAssetWritePolicy(before: EntityRelationRows, after: EntityRelationRows): void;
|
|
626
1052
|
/** Add only missing editor structure; existing identities and owned settings are never replaced. */
|
|
@@ -629,19 +1055,27 @@ declare function ensureEditorFoundation(initial: EntityRelationRows, idFactory?:
|
|
|
629
1055
|
//#region src/entity-editor/media-asset-import.d.ts
|
|
630
1056
|
interface ImportedMediaAsset {
|
|
631
1057
|
readonly rows: EntityRelationRows;
|
|
632
|
-
/** The
|
|
1058
|
+
/** The media entity for this asset id. */
|
|
633
1059
|
readonly contentEntityId: string;
|
|
1060
|
+
/** The Asset the media was made from; shared by every entity naming the same bytes. */
|
|
1061
|
+
readonly assetEntityId: string;
|
|
1062
|
+
/** The timbre identity of a synthesized voiceover; absent for recorded media. */
|
|
1063
|
+
readonly voiceEntityId?: string;
|
|
1064
|
+
}
|
|
1065
|
+
interface ImportedCaptionAsset {
|
|
1066
|
+
readonly rows: EntityRelationRows;
|
|
1067
|
+
readonly assetEntityId: string;
|
|
634
1068
|
}
|
|
1069
|
+
/** Import only the fixed ASR artifact; Caption entities are authored separately. */
|
|
1070
|
+
declare function importCaptionAsset(initial: EntityRelationRows, fact: CaptionAssetFact, idFactory?: EntityTimelineIdFactory): ImportedCaptionAsset;
|
|
635
1071
|
/**
|
|
636
1072
|
* Import at the editor boundary, not at asset generation time. Existing
|
|
637
1073
|
* provenance is retained.
|
|
638
1074
|
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
* the
|
|
642
|
-
*
|
|
643
|
-
* (`asset` row plus a `physical-asset` binding) are not reused and are
|
|
644
|
-
* rejected by the canonical resource policy instead of being migrated.
|
|
1075
|
+
* The bytes are named once, on an Asset entity, and the media entity reaches
|
|
1076
|
+
* them through a `from-asset` Relation. Re-importing the same `(system, key)`
|
|
1077
|
+
* reuses that Asset and the media already made from it, so one stored resource
|
|
1078
|
+
* is never copied into several rows.
|
|
645
1079
|
*/
|
|
646
1080
|
declare function importMediaAsset(initial: EntityRelationRows, fact: MediaAssetFact, idFactory?: EntityTimelineIdFactory): ImportedMediaAsset;
|
|
647
1081
|
//#endregion
|
|
@@ -670,164 +1104,12 @@ interface DocumentAudioScript {
|
|
|
670
1104
|
/** State exposing the current AudioScript content version attached to the project. */
|
|
671
1105
|
interface DocumentAudioScriptState {
|
|
672
1106
|
readonly rows: EntityRelationRows;
|
|
673
|
-
/** Current attachment
|
|
1107
|
+
/** Current attachment, or null until a script is transcribed or written. */
|
|
674
1108
|
readonly audioScriptEntityId: string | null;
|
|
675
1109
|
}
|
|
676
1110
|
/** Read only the attached version and preserve every segment; never aggregate other scripts. */
|
|
677
1111
|
declare function readDocumentAudioScript(state: DocumentAudioScriptState): DocumentAudioScript;
|
|
678
1112
|
//#endregion
|
|
679
|
-
//#region src/entity-crdt/field-changes.d.ts
|
|
680
|
-
/** List members are addressed by identity, never a transient array offset. */
|
|
681
|
-
type FieldPath = readonly (string | {
|
|
682
|
-
elementId: string;
|
|
683
|
-
})[];
|
|
684
|
-
type FieldChange = {
|
|
685
|
-
op: 'set';
|
|
686
|
-
path: FieldPath;
|
|
687
|
-
value: JsonValue;
|
|
688
|
-
} | {
|
|
689
|
-
op: 'unset';
|
|
690
|
-
path: FieldPath;
|
|
691
|
-
} | {
|
|
692
|
-
op: 'text.splice';
|
|
693
|
-
path: FieldPath;
|
|
694
|
-
index: number;
|
|
695
|
-
deleteCount: number;
|
|
696
|
-
text: string;
|
|
697
|
-
} | {
|
|
698
|
-
op: 'list.insert';
|
|
699
|
-
path: FieldPath;
|
|
700
|
-
value: JsonValue;
|
|
701
|
-
beforeElementId: string | null;
|
|
702
|
-
} | {
|
|
703
|
-
op: 'list.move';
|
|
704
|
-
path: FieldPath;
|
|
705
|
-
elementId: string;
|
|
706
|
-
beforeElementId: string | null;
|
|
707
|
-
} | {
|
|
708
|
-
op: 'list.remove';
|
|
709
|
-
path: FieldPath;
|
|
710
|
-
elementId: string;
|
|
711
|
-
};
|
|
712
|
-
declare function assertFieldChanges(changes: readonly FieldChange[]): void;
|
|
713
|
-
/** Resolve against the sequential causal view; the numeric path never crosses the API boundary. */
|
|
714
|
-
declare function resolveFieldPath(payload: JsonObject, path: FieldPath): (string | number)[];
|
|
715
|
-
/** Detached plan evaluation. Native compilation replays the original operations, not this snapshot. */
|
|
716
|
-
declare function applyFieldChanges(payload: JsonObject, changes: readonly FieldChange[]): JsonObject;
|
|
717
|
-
//#endregion
|
|
718
|
-
//#region src/entity-crdt/entity-document.d.ts
|
|
719
|
-
declare const LORO_ENTITY_SCHEMA = "medeo.entities.loro.v1";
|
|
720
|
-
interface EntityDocumentState {
|
|
721
|
-
readonly rows: EntityRelationRows;
|
|
722
|
-
readonly project: Readonly<Record<string, string>>;
|
|
723
|
-
}
|
|
724
|
-
type Command = {
|
|
725
|
-
type: 'create';
|
|
726
|
-
row: EntityRow;
|
|
727
|
-
} | {
|
|
728
|
-
type: 'selection-baseline';
|
|
729
|
-
root: string;
|
|
730
|
-
fingerprint: string;
|
|
731
|
-
} | {
|
|
732
|
-
type: 'order';
|
|
733
|
-
group: string;
|
|
734
|
-
roots: string[];
|
|
735
|
-
token: string;
|
|
736
|
-
} | {
|
|
737
|
-
type: 'write';
|
|
738
|
-
root: string;
|
|
739
|
-
payload: JsonObject;
|
|
740
|
-
token: string;
|
|
741
|
-
} | {
|
|
742
|
-
type: 'text';
|
|
743
|
-
root: string;
|
|
744
|
-
path: readonly (string | number)[];
|
|
745
|
-
start: number;
|
|
746
|
-
deleteCount: number;
|
|
747
|
-
text: string;
|
|
748
|
-
token: string;
|
|
749
|
-
} | {
|
|
750
|
-
type: 'field';
|
|
751
|
-
root: string;
|
|
752
|
-
path: (string | number)[];
|
|
753
|
-
change: FieldChange;
|
|
754
|
-
token: string;
|
|
755
|
-
} | {
|
|
756
|
-
type: 'relation-field';
|
|
757
|
-
root: string;
|
|
758
|
-
path: (string | number)[];
|
|
759
|
-
change: FieldChange;
|
|
760
|
-
} | {
|
|
761
|
-
type: 'delete';
|
|
762
|
-
root: string;
|
|
763
|
-
} | {
|
|
764
|
-
type: 'relation';
|
|
765
|
-
row: RelationRow;
|
|
766
|
-
} | {
|
|
767
|
-
type: 'relation-fields';
|
|
768
|
-
root: string;
|
|
769
|
-
metadata: JsonObject;
|
|
770
|
-
trace: JsonObject;
|
|
771
|
-
} | {
|
|
772
|
-
type: 'unlink';
|
|
773
|
-
root: string;
|
|
774
|
-
} | {
|
|
775
|
-
type: 'attach';
|
|
776
|
-
slot: string;
|
|
777
|
-
entityId: string;
|
|
778
|
-
};
|
|
779
|
-
/** Plain domain objects assembled from native Loro state, never a second writable authority. */
|
|
780
|
-
declare function readEntityDocument(doc: LoroDoc, allowSelectionConflicts?: boolean): EntityDocumentState;
|
|
781
|
-
/** Native editing containers survive domain version changes and merge independently. */
|
|
782
|
-
declare class LoroEntityDocument {
|
|
783
|
-
readonly doc: LoroDoc;
|
|
784
|
-
private readonly validate?;
|
|
785
|
-
private readonly undoManager;
|
|
786
|
-
constructor(doc: LoroDoc, validate?: ((state: EntityDocumentState) => void) | undefined);
|
|
787
|
-
/** Open a causal snapshot using the same Loro runtime as the compiler. */
|
|
788
|
-
static fromSnapshot(snapshot: Uint8Array, validate?: (state: EntityDocumentState) => void): LoroEntityDocument;
|
|
789
|
-
static create(rows: EntityRelationRows, project?: Readonly<Record<string, string>>, peerId?: PeerID): LoroEntityDocument;
|
|
790
|
-
snapshot(): EntityDocumentState;
|
|
791
|
-
relationsOf(entityId: string): readonly RelationRow[];
|
|
792
|
-
getVersion(id: string): EntityRow | undefined;
|
|
793
|
-
/** The callback and every domain validation execute on a causally complete fork first. */
|
|
794
|
-
transact(edit: (draft: LoroEntityDraft) => void): Uint8Array;
|
|
795
|
-
/** Import preserves native operation identities; projection errors never discard remote operations. */
|
|
796
|
-
import(update: Uint8Array): void;
|
|
797
|
-
canUndo(): boolean;
|
|
798
|
-
canRedo(): boolean;
|
|
799
|
-
undo(): boolean;
|
|
800
|
-
redo(): boolean;
|
|
801
|
-
private historyEdit;
|
|
802
|
-
}
|
|
803
|
-
declare class LoroEntityDraft {
|
|
804
|
-
private readonly doc;
|
|
805
|
-
readonly commands: Command[];
|
|
806
|
-
private readonly selectedRoots;
|
|
807
|
-
private readonly relationAliases;
|
|
808
|
-
constructor(doc: LoroDoc);
|
|
809
|
-
snapshot(): EntityDocumentState;
|
|
810
|
-
order(groupId: string, entityIds: readonly string[]): void;
|
|
811
|
-
/** Project the final scalar placement intents onto the existing native ordering containers. */
|
|
812
|
-
reconcileOrder(rows: EntityRelationRows): void;
|
|
813
|
-
create(row: EntityRow): void;
|
|
814
|
-
delete(entityId: string): void;
|
|
815
|
-
attach(slot: string, entityId: string): void;
|
|
816
|
-
link(row: RelationRow): void;
|
|
817
|
-
patchRelation(relationId: string, metadata: JsonObject, trace: JsonObject): void;
|
|
818
|
-
unlink(relationId: string): void;
|
|
819
|
-
private relationRoot;
|
|
820
|
-
update(entityId: string, fields: JsonObject): void;
|
|
821
|
-
declare(entityId: string, fields: JsonObject): void;
|
|
822
|
-
replaceOwned(entityId: string, payload: JsonObject): void;
|
|
823
|
-
editText(entityId: string, path: readonly (string | number)[], start: number, deleteCount: number, text: string): void;
|
|
824
|
-
/** Generic assembled-field edit compiled at the author's causal position. */
|
|
825
|
-
change(entityId: string, changes: readonly FieldChange[]): void;
|
|
826
|
-
changeRelation(relationId: string, changes: readonly FieldChange[]): void;
|
|
827
|
-
captureSelectionBaselines(): void;
|
|
828
|
-
private record;
|
|
829
|
-
}
|
|
830
|
-
//#endregion
|
|
831
1113
|
//#region src/entity-crdt/compile-rows.d.ts
|
|
832
1114
|
/** Lower a detached ordinary-object edit against its actual causal Loro baseline. */
|
|
833
1115
|
declare function compileEntityRows(snapshot: Uint8Array, rows: EntityRelationRows, validate?: (state: EntityDocumentState) => void): {
|
|
@@ -949,7 +1231,9 @@ type PushResultKind = 'ack' | 'duplicate' | 'rejected' | 'failed' | 'nothing_to_
|
|
|
949
1231
|
*/
|
|
950
1232
|
interface PushResult {
|
|
951
1233
|
kind: PushResultKind;
|
|
952
|
-
/** Server
|
|
1234
|
+
/** Server document sequence observed after a successful `ack` or `duplicate`. */
|
|
1235
|
+
mengineUpdateSeq?: number | undefined;
|
|
1236
|
+
/** @deprecated Ack-only sequence retained until consumers adopt `mengineUpdateSeq`. */
|
|
953
1237
|
updateSeq?: number | undefined;
|
|
954
1238
|
/** Whether the server held ops the local document lacked. See above. */
|
|
955
1239
|
collaborated: boolean;
|
|
@@ -1043,6 +1327,8 @@ declare class ManualSyncDoc {
|
|
|
1043
1327
|
private readonly client;
|
|
1044
1328
|
private readonly doc;
|
|
1045
1329
|
private readonly adapter;
|
|
1330
|
+
/** Whether this document's timeline is owned by the Entity graph. */
|
|
1331
|
+
isEntityDocument(): boolean;
|
|
1046
1332
|
readonly editor: SemanticEditor;
|
|
1047
1333
|
/**
|
|
1048
1334
|
* The version the server is known to hold. Starts empty (nothing confirmed)
|
|
@@ -1056,8 +1342,7 @@ declare class ManualSyncDoc {
|
|
|
1056
1342
|
* Fetches the snapshot up front rather than starting empty and converging: the
|
|
1057
1343
|
* agent's first act is to read the document, so there is no useful state before
|
|
1058
1344
|
* the snapshot lands. This also fails fast and loudly on a document that does
|
|
1059
|
-
* not exist
|
|
1060
|
-
* waiting forever for content that will never arrive.
|
|
1345
|
+
* not exist or whose first snapshot is incomplete or invalid.
|
|
1061
1346
|
*/
|
|
1062
1347
|
static open(options: ManualSyncDocOptions): Promise<ManualSyncDoc>;
|
|
1063
1348
|
/** Current document read model (authoritative shape). */
|
|
@@ -1073,8 +1358,8 @@ declare class ManualSyncDoc {
|
|
|
1073
1358
|
* was passed to the constructor.
|
|
1074
1359
|
*/
|
|
1075
1360
|
editorPeerId(): PeerID;
|
|
1076
|
-
/** Current
|
|
1077
|
-
|
|
1361
|
+
/** Current content projected into the compatible track and part read shape. */
|
|
1362
|
+
content(): VideoDraftContent;
|
|
1078
1363
|
/**
|
|
1079
1364
|
* Replay a deterministic sandbox journal into this document.
|
|
1080
1365
|
*
|
|
@@ -1091,9 +1376,8 @@ declare class ManualSyncDoc {
|
|
|
1091
1376
|
*
|
|
1092
1377
|
* This pair replaces the legacy integer-version comparison that
|
|
1093
1378
|
* `DraftVersionDetector` used to tell the LLM "the draft was modified
|
|
1094
|
-
* externally, reload before editing".
|
|
1095
|
-
*
|
|
1096
|
-
* vectors restores the same capability.
|
|
1379
|
+
* externally, reload before editing". Comparing Loro version vectors covers
|
|
1380
|
+
* all collaborative edits without a business revision field in the document.
|
|
1097
1381
|
*
|
|
1098
1382
|
* Same capability, not a stronger one: like the legacy detector, this only
|
|
1099
1383
|
* reports what changed between two moments the caller chose to sample.
|
|
@@ -1238,12 +1522,24 @@ declare class MedeoHttpDocStorage implements DocStorage {
|
|
|
1238
1522
|
* tool-level ack wait) subscribe here.
|
|
1239
1523
|
*/
|
|
1240
1524
|
subscribePushOutcome(callback: (outcome: PushOutcome) => void): () => void;
|
|
1525
|
+
/** Observe live hints that require VV catch-up without replacing the SSE connection. */
|
|
1526
|
+
subscribeResync(callback: () => void): () => void;
|
|
1527
|
+
/** Authoritative HTTP reads and accepted pushes, never inferred from SSE bytes. */
|
|
1528
|
+
subscribeServerVersion(callback: (version: Uint8Array) => void): () => void;
|
|
1529
|
+
private reportServerVersion;
|
|
1241
1530
|
deleteDoc(_docId: string): Promise<void>;
|
|
1242
1531
|
subscribeDocUpdate(callback: (update: DocUpdate, origin: unknown) => void): () => void;
|
|
1243
1532
|
private assertDocId;
|
|
1244
1533
|
private emitUpdate;
|
|
1245
1534
|
}
|
|
1246
1535
|
//#endregion
|
|
1536
|
+
//#region src/session/document-undo-manager.d.ts
|
|
1537
|
+
/** Availability for this document's current editing session, not server revisions. */
|
|
1538
|
+
interface MengineUndoState {
|
|
1539
|
+
readonly canUndo: boolean;
|
|
1540
|
+
readonly canRedo: boolean;
|
|
1541
|
+
}
|
|
1542
|
+
//#endregion
|
|
1247
1543
|
//#region src/session/types.d.ts
|
|
1248
1544
|
/**
|
|
1249
1545
|
* Local storage contract the runtime depends on. Aliased to the engine
|
|
@@ -1286,6 +1582,14 @@ interface WaitForServerAckOptions {
|
|
|
1286
1582
|
/** Deadline in ms. Rejects with reason `timeout` when it elapses. */
|
|
1287
1583
|
timeoutMs?: number;
|
|
1288
1584
|
}
|
|
1585
|
+
/** Document-level confirmation is independent of local operation completion. */
|
|
1586
|
+
interface MengineDocSyncState {
|
|
1587
|
+
/** Remote-only imports do not create a new local confirmation obligation. */
|
|
1588
|
+
readonly confirmation: 'unknown' | 'pending' | 'confirmed';
|
|
1589
|
+
/** Transport/activity phase. Idle does not imply confirmation; failure details
|
|
1590
|
+
* remain available through push outcomes and confirmation wait errors. */
|
|
1591
|
+
readonly phase: 'connecting' | 'idle' | 'syncing' | 'offline' | 'failed';
|
|
1592
|
+
}
|
|
1289
1593
|
interface MengineDocSessionOptions {
|
|
1290
1594
|
docId: string;
|
|
1291
1595
|
client: MengineHttpClient;
|
|
@@ -1306,13 +1610,9 @@ interface MengineDocSessionOptions {
|
|
|
1306
1610
|
* A live editing session for one Medeo document — the single entry point clients
|
|
1307
1611
|
* (FE draft driver, Agent, embeds) use to open, edit, and observe a document.
|
|
1308
1612
|
*
|
|
1309
|
-
*
|
|
1310
|
-
*
|
|
1311
|
-
*
|
|
1312
|
-
* ├─ ClientServerSynchronizer ── DocManager ── LoroDoc
|
|
1313
|
-
* MedeoHttpDocStorage┘ │
|
|
1314
|
-
* (remote = Rust mengine-server) ▼
|
|
1315
|
-
* MirrorVideoDocumentAdapter + SemanticEditor
|
|
1613
|
+
* SemanticEditor writes through MirrorVideoDocumentAdapter directly, while
|
|
1614
|
+
* DocumentUndoManager observes the same LoroDoc independently. Both mutation
|
|
1615
|
+
* paths use the session's DocumentMutationGuard, closed before teardown.
|
|
1316
1616
|
*
|
|
1317
1617
|
* `DocManager` owns the `LoroDoc`: local edits committed on the adapter are
|
|
1318
1618
|
* picked up via `subscribeLocalUpdates`, saved to local storage, then pushed to
|
|
@@ -1333,11 +1633,20 @@ declare class MengineDocSession {
|
|
|
1333
1633
|
private readonly manager;
|
|
1334
1634
|
private readonly events;
|
|
1335
1635
|
private readonly disposables;
|
|
1636
|
+
private readonly mutationGuard;
|
|
1336
1637
|
private adapterValue;
|
|
1337
1638
|
private editorValue;
|
|
1639
|
+
private undoManagerValue;
|
|
1338
1640
|
private started;
|
|
1641
|
+
private startTask;
|
|
1642
|
+
private destroyed;
|
|
1643
|
+
private lifetime;
|
|
1644
|
+
private hasConnected;
|
|
1645
|
+
private initialVersionValue;
|
|
1646
|
+
private localVersionValue;
|
|
1647
|
+
private pushErrorValue;
|
|
1339
1648
|
/**
|
|
1340
|
-
* Latest server oplog version seen on
|
|
1649
|
+
* Latest server oplog version seen on an authoritative HTTP response. Lets `waitForServerAck`
|
|
1341
1650
|
* return without waiting when the server is already known to cover the local
|
|
1342
1651
|
* doc (e.g. nothing was edited since the last confirmed push).
|
|
1343
1652
|
*/
|
|
@@ -1352,14 +1661,14 @@ declare class MengineDocSession {
|
|
|
1352
1661
|
*/
|
|
1353
1662
|
subscribePushOutcome(callback: (outcome: PushOutcome) => void): () => void;
|
|
1354
1663
|
/**
|
|
1355
|
-
* Resolve once the server has durably accepted the local
|
|
1664
|
+
* Resolve once the server has durably accepted the local commits as of
|
|
1356
1665
|
* *now* — the capability an Agent tool needs to answer "did my edit land?"
|
|
1357
1666
|
* before reporting success.
|
|
1358
1667
|
*
|
|
1359
1668
|
* Call it right after the editor ops whose durability matters. It snapshots the
|
|
1360
|
-
* local
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1669
|
+
* latest local commit's version (or the loaded baseline before any edit) and
|
|
1670
|
+
* resolves when an authoritative server version covers it. Remote-only
|
|
1671
|
+
* imports do not extend this target, matching the displayed confirmation state.
|
|
1363
1672
|
*
|
|
1364
1673
|
* Version coverage, not byte identity, is the acceptance test — for two reasons:
|
|
1365
1674
|
* the ops may reach the server inside a merged blob rather than as the exact
|
|
@@ -1395,29 +1704,58 @@ declare class MengineDocSession {
|
|
|
1395
1704
|
get documentAdapter(): SemanticDocumentAdapter;
|
|
1396
1705
|
/** Current document snapshot (read model). */
|
|
1397
1706
|
snapshot(): VideoDocument;
|
|
1707
|
+
/** Current-session undo/redo availability. Loading and closed sessions report false. */
|
|
1708
|
+
getUndoState(): MengineUndoState;
|
|
1709
|
+
/**
|
|
1710
|
+
* Supplies current availability immediately, then coalesces stack changes in a
|
|
1711
|
+
* microtask. Session teardown publishes empty availability synchronously.
|
|
1712
|
+
*/
|
|
1713
|
+
subscribeUndoState(cb: (state: MengineUndoState) => void): () => void;
|
|
1714
|
+
/**
|
|
1715
|
+
* Undo a local edit immediately; server confirmation remains asynchronous.
|
|
1716
|
+
* On a shared LWW field this writes its prior value, potentially overwriting a
|
|
1717
|
+
* later remote edit to that same field. Returns false if no update is produced.
|
|
1718
|
+
*/
|
|
1719
|
+
undo(options?: CommitOptions): boolean;
|
|
1720
|
+
/**
|
|
1721
|
+
* Restore the state visible before undo without rerunning external side effects.
|
|
1722
|
+
* Returns false if no update is produced; durable confirmation is separate.
|
|
1723
|
+
*/
|
|
1724
|
+
redo(options?: CommitOptions): boolean;
|
|
1725
|
+
/**
|
|
1726
|
+
* Combine existing semantic operations (e.g. trim a clip and adjust its volume)
|
|
1727
|
+
* or repeated commits during one drag gesture into a single undo step. A gesture
|
|
1728
|
+
* that only previews locally and commits once on release needs no group.
|
|
1729
|
+
* Each commit is immediately visible locally and enters sync independently;
|
|
1730
|
+
* a later failure does not roll it back.
|
|
1731
|
+
* Always pair with endUndoGroup in a finally block. Conflicting remote imports
|
|
1732
|
+
* can end/split the group early, and unrelated local edits would join it.
|
|
1733
|
+
* Complete asynchronous asset preparation before opening the group.
|
|
1734
|
+
*/
|
|
1735
|
+
beginUndoGroup(): void;
|
|
1736
|
+
/** End a gesture, including one already split by a conflicting remote import. */
|
|
1737
|
+
endUndoGroup(): void;
|
|
1398
1738
|
/**
|
|
1399
1739
|
* Start the sync stack and connect the document.
|
|
1400
1740
|
*
|
|
1401
|
-
* Returns
|
|
1402
|
-
*
|
|
1403
|
-
*
|
|
1741
|
+
* Returns after DocManager loads a local snapshot, or after the first remote
|
|
1742
|
+
* sync when no local snapshot exists. A valid empty document is ready too.
|
|
1743
|
+
* Cached documents can open before SSE connects; subsequent remote changes
|
|
1744
|
+
* surface through `subscribe`.
|
|
1404
1745
|
*/
|
|
1405
1746
|
start(): Promise<VideoDocument>;
|
|
1747
|
+
private open;
|
|
1748
|
+
getSyncState(): MengineDocSyncState;
|
|
1749
|
+
private confirmationTarget;
|
|
1750
|
+
/** Immediately supplies current state; unsubscribe when the host changes docs. */
|
|
1751
|
+
subscribeSyncState(cb: (state: MengineDocSyncState) => void): () => void;
|
|
1752
|
+
private emitSyncState;
|
|
1406
1753
|
subscribe(cb: (event: MengineDocSessionUpdateEvent) => void): () => void;
|
|
1407
1754
|
onStateChange(cb: (state: DocState) => void): () => void;
|
|
1408
1755
|
getState(): DocState;
|
|
1409
1756
|
destroy(): void;
|
|
1410
|
-
/**
|
|
1411
|
-
|
|
1412
|
-
*
|
|
1413
|
-
* `DocManager` loads from local storage, which starts empty for a fresh
|
|
1414
|
-
* client; the server snapshot arrives asynchronously via the first sync job.
|
|
1415
|
-
* `loaded` only means the local load ran, so we wait for actual content
|
|
1416
|
-
* (populated schema roots) instead, surfaced by the doc subscription set up
|
|
1417
|
-
* in `start()`.
|
|
1418
|
-
*/
|
|
1419
|
-
private waitForContent;
|
|
1420
|
-
private hasContent;
|
|
1757
|
+
/** Local absence needs a remote sync; empty business content does not. */
|
|
1758
|
+
private waitForInitialLoad;
|
|
1421
1759
|
}
|
|
1422
1760
|
//#endregion
|
|
1423
1761
|
//#region src/storage/memory-doc-storage.d.ts
|
|
@@ -1604,103 +1942,6 @@ type MakeEmptyPart = (durationMs: number) => {
|
|
|
1604
1942
|
*/
|
|
1605
1943
|
declare function cascadeAfterVideoClipChanges(doc: TimelineDoc, makeEmptyPart: MakeEmptyPart): void;
|
|
1606
1944
|
//#endregion
|
|
1607
|
-
//#region src/timeline-core/bridge.d.ts
|
|
1608
|
-
/**
|
|
1609
|
-
* Bridge between the authoritative `VideoDocument` (position-only facts) and the
|
|
1610
|
-
* flat `TimelineDoc` the cascade primitives solve over.
|
|
1611
|
-
*
|
|
1612
|
-
* The data flow is single-directional (RFC 02 §7/§10): ops write only facts
|
|
1613
|
-
* (`time_position`, parts) to `VideoDocument`; absolute time, `part_aggregations`,
|
|
1614
|
-
* total duration, and gap fillers are NOT stored — the projection derives them
|
|
1615
|
-
* on read by running the cascade. There is no write-back of solved positions.
|
|
1616
|
-
*
|
|
1617
|
-
* - `solveVideoDocument` seeds a `TimelineDoc` from each item's `time_position`,
|
|
1618
|
-
* runs the full cascade, and returns the derived read-view (abs / aggregations
|
|
1619
|
-
* / duration). It is the single solve shared by the legacy `VideoDraft`
|
|
1620
|
-
* projection.
|
|
1621
|
-
* - `ensureLaneTrack` / `findLaneTrack` locate (or mint) a secondary lane's
|
|
1622
|
-
* track row in the draft, so ops can write authoritative facts onto the right
|
|
1623
|
-
* named container (lane = container).
|
|
1624
|
-
*/
|
|
1625
|
-
/** The projection-derived read-view of a `VideoDocument` (RFC 02 §7). */
|
|
1626
|
-
interface SolvedVideoDocument {
|
|
1627
|
-
absByPartId: Map<string, number>;
|
|
1628
|
-
aggregations: PartAggregation[];
|
|
1629
|
-
durationMs: number;
|
|
1630
|
-
partLibrary: Record<string, PartUnion>;
|
|
1631
|
-
/**
|
|
1632
|
-
* Part ids of the gap fillers this solve minted.
|
|
1633
|
-
*
|
|
1634
|
-
* They exist only inside the solve: gap filling needs them so the clips after a
|
|
1635
|
-
* gap land at the right absolute time, but they are not authoritative state and
|
|
1636
|
-
* the read view does not carry them (see `fromVideoDocument`).
|
|
1637
|
-
*
|
|
1638
|
-
* Reported as ids rather than left for the caller to detect, because the caller
|
|
1639
|
-
* *cannot* detect them. The obvious predicate — `origin_media_id === ''` — also
|
|
1640
|
-
* matches an empty clip a writer placed on purpose (`batch_replace_video_clip_sequence`
|
|
1641
|
-
* documents "Omit to create an empty clip placeholder"), and those are
|
|
1642
|
-
* authoritative parts that must survive the projection. The mint callback is the
|
|
1643
|
-
* only place that knows the difference.
|
|
1644
|
-
*
|
|
1645
|
-
* Note this deliberately excludes the fillers that gap filling *extended* rather
|
|
1646
|
-
* than minted (`fillMainTrackTimeGaps` cases 1 and 2): those are authoritative
|
|
1647
|
-
* empty clips already in `part_library`, and only their length is derived.
|
|
1648
|
-
*/
|
|
1649
|
-
derivedFillerPartIds: Set<string>;
|
|
1650
|
-
}
|
|
1651
|
-
/**
|
|
1652
|
-
* Solve a `VideoDocument` (authoritative, position-only) into its derived
|
|
1653
|
-
* read-view: absolute time per item, `part_aggregations`, and total duration.
|
|
1654
|
-
* This is the read side of the single-directional flow — never written back.
|
|
1655
|
-
*/
|
|
1656
|
-
declare function solveVideoDocument(document: VideoDocument): SolvedVideoDocument;
|
|
1657
|
-
/** The named container a secondary lane lives in. */
|
|
1658
|
-
type SecondaryLane = 'speech' | 'caption' | 'bgm';
|
|
1659
|
-
/** A lane's track kind: the `video_clip` main lane plus the three secondary lanes. */
|
|
1660
|
-
type LaneKind = SecondaryLane | 'video_clip';
|
|
1661
|
-
/**
|
|
1662
|
-
* The four lanes in top-to-bottom stack order — the order a `tracks` list holds
|
|
1663
|
-
* them in (see {@link laneRank}).
|
|
1664
|
-
*
|
|
1665
|
-
* Exported so a document can be seeded with all four lanes up front. That seed is
|
|
1666
|
-
* not cosmetic: {@link ensureLaneTrack} is find-then-mint over a `LoroMovableList`,
|
|
1667
|
-
* so two concurrent writers that each mint the same absent lane both keep their
|
|
1668
|
-
* row, and the merged document holds two tracks for one lane. For the main lane
|
|
1669
|
-
* that is fatal — `videoDocumentSchema` allows at most one `video_clip` track, so
|
|
1670
|
-
* the merged document stops being projectable at all, symmetrically on both
|
|
1671
|
-
* replicas. Pre-seeding every lane makes `ensureLaneTrack` always take its find
|
|
1672
|
-
* branch, which removes the race by construction rather than by detection.
|
|
1673
|
-
*
|
|
1674
|
-
* What closes the race is that a track with the lane's `parts_kind` EXISTS — the
|
|
1675
|
-
* lookup is by kind, not by id. So a seed is only safe if it covers every lane:
|
|
1676
|
-
* a partial seed leaves the uncovered lanes exactly as exposed as before.
|
|
1677
|
-
*/
|
|
1678
|
-
declare const LANE_KINDS_IN_STACK_ORDER: readonly LaneKind[];
|
|
1679
|
-
/**
|
|
1680
|
-
* The conventional track id for a lane (`main_track`, `<kind>_track`). Shared by
|
|
1681
|
-
* the up-front seed and {@link ensureLaneTrack}'s lazy mint so a document's lane
|
|
1682
|
-
* ids do not depend on which of the two created the track.
|
|
1683
|
-
*
|
|
1684
|
-
* Ids are cosmetic to the merge itself — lane lookup goes by `parts_kind`, so
|
|
1685
|
-
* drifting them apart would not reopen the concurrent-mint race. They matter to
|
|
1686
|
-
* readers that address a lane by id (the FE editor's panes, fixtures), which is
|
|
1687
|
-
* why there is one convention rather than two.
|
|
1688
|
-
*/
|
|
1689
|
-
declare function laneTrackId(kind: LaneKind): string;
|
|
1690
|
-
/**
|
|
1691
|
-
* Locate a lane's track row in the single `tracks` list by kind, minting an empty
|
|
1692
|
-
* row in lane-stacking order if absent (reference/17 §4: lane = `parts_kind`).
|
|
1693
|
-
* Ops use this to write authoritative items onto the right lane. The track id
|
|
1694
|
-
* comes from {@link laneTrackId}, shared with the up-front seed.
|
|
1695
|
-
*
|
|
1696
|
-
* The mint branch is a concurrency hazard, not a convenience: see
|
|
1697
|
-
* {@link LANE_KINDS_IN_STACK_ORDER}. A document seeded with all four lanes never
|
|
1698
|
-
* reaches it.
|
|
1699
|
-
*/
|
|
1700
|
-
declare function ensureLaneTrack(draft: VideoDocumentDraft, kind: LaneKind): TrackDraft;
|
|
1701
|
-
/** Find a secondary lane's track row without minting it. */
|
|
1702
|
-
declare function findLaneTrack(draft: VideoDocumentDraft, kind: SecondaryLane): TrackDraft | undefined;
|
|
1703
|
-
//#endregion
|
|
1704
1945
|
//#region src/timeline-core/locate.d.ts
|
|
1705
1946
|
/**
|
|
1706
1947
|
* Forward positioning for write-time ops (RFC 02 §9.1) — NOT a cascade.
|
|
@@ -1744,4 +1985,37 @@ declare function hostForAbsMs(ranges: MainClipRange[], absMs: number): MainClipR
|
|
|
1744
1985
|
*/
|
|
1745
1986
|
declare function relativePositionForAbs(ranges: MainClipRange[], absMs: number): TrackItemTimePosition;
|
|
1746
1987
|
//#endregion
|
|
1747
|
-
|
|
1988
|
+
//#region src/entity-crdt/audio-script-assets.d.ts
|
|
1989
|
+
/** A resource is a snapshot of text; the native Loro text remains the editing authority. */
|
|
1990
|
+
declare function audioScriptAssetContent(payload: JsonObject): JsonObject;
|
|
1991
|
+
declare function audioScriptAssetHash(payload: JsonObject): string;
|
|
1992
|
+
/**
|
|
1993
|
+
* The Asset a script was written out to. It is a snapshot the script owns, so
|
|
1994
|
+
* it is reached by `to-asset` — not `from-asset`, which would say the script
|
|
1995
|
+
* was produced from bytes it cannot change.
|
|
1996
|
+
*/
|
|
1997
|
+
declare function audioScriptAssetOf(rows: EntityRelationRows, entityId: string): EntityRow | undefined;
|
|
1998
|
+
/**
|
|
1999
|
+
* The Asset a script was made from — a transcript it does not own. A script
|
|
2000
|
+
* that has one never writes a snapshot of its own: the bytes it would describe
|
|
2001
|
+
* are already named, and rewriting them would contradict their source.
|
|
2002
|
+
*/
|
|
2003
|
+
declare function scriptSourceAssetOf(rows: EntityRelationRows, entityId: string): EntityRow | undefined;
|
|
2004
|
+
/** Internal fingerprint prevents a resource from silently describing an older text revision. */
|
|
2005
|
+
declare function audioScriptAssetFields(payload: JsonObject): JsonObject;
|
|
2006
|
+
/**
|
|
2007
|
+
* What a PhoneticScript hands to synthesis: the base AudioScript's text as the
|
|
2008
|
+
* variant pronounces it, plus the variant's own phoneme and prosody control.
|
|
2009
|
+
*
|
|
2010
|
+
* The variant's content is written by a model — deciding how words are said is
|
|
2011
|
+
* text work, not a mechanical copy — but the bytes a synthesizer reads have to
|
|
2012
|
+
* leave the entity graph to reach it, because synthesis does not handle
|
|
2013
|
+
* entities. Writing this resource down is that crossing, and it is why speech
|
|
2014
|
+
* can only come from a PhoneticScript.
|
|
2015
|
+
*/
|
|
2016
|
+
declare function phoneticScriptAssetContent(rows: EntityRelationRows, entityId: string): JsonObject;
|
|
2017
|
+
declare function phoneticScriptAssetHash(rows: EntityRelationRows, entityId: string): string;
|
|
2018
|
+
/** The Asset a PhoneticScript was written out to, read from the graph. */
|
|
2019
|
+
declare function phoneticScriptAssetOf(rows: EntityRelationRows, entityId: string): EntityRow | undefined;
|
|
2020
|
+
//#endregion
|
|
2021
|
+
export { type AddGeneratedVisualsInput, type AddSpeechAssetsInput, type Aggregation, type ApplyCaptionAssetsInput, type ApplyCaptionAssetsResult, type AsrCaptionSegment, type AssembledCaptionContent, type AssembledPhoneticScriptContent, type Attachment, type AudioMediaAssetFact, type BgmPart, type CaptionAssetFact, type CaptionAssetsEffectEnvelope, type CaptionContentInput, type CaptionDisplayCue, type CaptionPart, type CaptionSegmentSelection, type CaptionStyle, type ClipEntityId, type ClipPlacement, type CommitOptions, type CompiledCaptionAssetsEffect, type CompiledGeneratedVisualEffect, type CompiledSpeechAssetsEffect, type ContinueVideoInput, DEFAULT_UNIT_TIME_MS, type DeleteBgmInput, type DeleteClipInput, type DeleteClipTreeInput, type DeleteVoiceoverInput, type DerivedItemPosition, type DocStorageLike, type DocVersionMark, type DocumentAudioScript, type DocumentAudioScriptState, type EditorFoundation, EntityDocumentState, type EntityGraphCommitOptions, EntityGraphHttpClient, type EntityGraphState, EntityTimelineEditor, type EntityTimelineIdFactory, type EntityTimelineProjectionDocument, EntityTimelineProjectionError, type EntityTimelineTrackRole, type FieldChange, type FieldPath, type GeneratedSpeechCaptionFact, type GeneratedSpeechFact, type GeneratedSpeechSourceFact, type GeneratedVisualClipFact, type GeneratedVisualEffectEnvelope, type GeneratedVisualEffectResult, IMPLEMENTED_SEMANTIC_OP_KINDS, type ImageMediaAssetFact, type ImplementedSemanticOpKind, type ImportedCaptionAsset, type ImportedMediaAsset, type InsertCaptionClipInput, type InsertClipInput, type InsertMediaClipInput, type InsertMediaClipsInput, type InsertPlacedClipInput, type JournalEntry, LANE_KINDS_IN_STACK_ORDER, LORO_ENTITY_SCHEMA, type LaneKind, type LinearClipSpeed, LoroEntityDocument, LoroEntityDraft, type MainClipRange, type MakeEmptyPart, ManualSyncDoc, type ManualSyncDocOptions, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type MediaAssetFact, type MediaClipInsertion, MemoryDocStorage, MengineAckFailedError, type MengineAuditEntry, type MengineAuditResponse, MengineDocSession, type MengineDocSessionOptions, type MengineDocSessionUpdateEvent, type MengineDocSyncState, type MengineDocumentVersion, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUndoState, type MengineUpdateMeta, MirrorVideoDocumentAdapter, type MirrorVideoDocumentOptions, type MoveClipInput, type MoveClipsToStartsInput, type MoveSequentialClipsInput, type MoveVoiceoverInput, type OpActor, type PartAggregation, type PartIdFactory, type PartKind, type PartUnion, type PatchCaptionStyleInput, PlainMemoryAdapter, type PlainMemoryAdapterOptions, type PlannedSemanticOpKind, type PullFailureReason, type PullResult, type PushOutcome, type PushOutcomeKind, type PushResult, type PushResultKind, type ReplaceClipContentInput, type ReplaceMediaClipInput, type ReplaceSequentialClipsInput, type ReplaceVoiceSpeechAssetsInput, type ReplacementMediaClipInput, type ResolvedAsrSpeechSegment, type ResolvedEntityClipPlacement, type ResolvedEntityTimelineLayout, type ResolvedEntityTrack, type ResolvedSpeechScriptSegment, SchemaValidator, ScriptCompositionError, type SemanticDocumentAdapter, SemanticEditor, type SemanticOpInput, type SemanticOpKind, type SemanticOpName, type SequentialClipAnchor, type SetBgmInput, type SetCaptionVisibilityInput, type SetClipPlacementInput, type SetClipSpeedInput, type SetClipVolumeInput, type SetVideoClipSpeedEffectInput, type SnapshotReadable, type SolvedVideoDocument, type SpeechAssetsEffectEnvelope, type SpeechAssetsEffectInput, type SpeechAssetsEffectResult, type SpeechHostMap, type SpeechOriginAssetSystem, type SpeechPart, type SpeedShift, TIMELINE_SKELETON_DURATION_MS, type Timeline, type TimelineDoc, type TimelineItem, type Track, type TrackDraft, type TrackItem, type TrackItemDraft, type TrackItemTimePosition, type TransactAudit, type TrimClipInput, type UpdateClipInput, type UpdateClipMarkerInput, ValidationError, type VideoClipPart, type VideoClipSpeedMode, type VideoDocument, type VideoDocumentDraft, type VideoDocumentMirrorSchema, VideoDocumentValidationError, type VideoDocumentValidationIssue, type VideoDocumentValidationIssueCode, type VideoDraft, type CaptionPart$1 as VideoDraftCaptionPart, type VideoDraftContent, type VideoDraftPartUnion, type Timeline$1 as VideoDraftTimeline, type Track$1 as VideoDraftTrack, type TrackItem$1 as VideoDraftTrackItem, type VideoMediaAssetFact, type VisualMediaAssetFact, type VoiceoverCaptionFact, type VoiceoverMediaAssetFact, type VoiceoverTakeInput, type VoiceoverTakeResult, type WaitForServerAckOptions, applyEntityRows, applyFieldChanges, arrangeMainTrackSeamlessly, assembleCaptionContent, assembleEntityContent, assemblePhoneticScriptContent, assembleScriptText, assertCanonicalEditorResources, assertEntityProjectionPreservesLegacy, assertFieldChanges, assertMediaAssetWritePolicy, assertValidVideoDocument, audioScriptAssetContent, audioScriptAssetFields, audioScriptAssetHash, audioScriptAssetOf, base64ToBytes, buildInitialVideoDocument, buildSpeechHostMap, bytesToBase64, cascadeAfterVideoClipChanges, compileCaptionAssetsEffect, compileEntityRows, compileGeneratedVisualEffect, compileSpeechAssetsEffect, createEditSandbox, createMirrorVideoDocument, createMirrorVideoDocumentAdapter, createPlainMemoryAdapter, decodeDocVersionMark, derivePositionFromAbs, effectiveVideoClipDurationMs, encodeDocVersionMark, ensureEditorFoundation, ensureLaneTrack, fillMainTrackTimeGaps, findComposedAudioScript, findLaneTrack, fromVideoDocument, generatePartId, getAt, hostForAbsMs, importCaptionAsset, importMediaAsset, isEmptyVideoClip, isImplementedSemanticOpKind, isMap, laneTrackId, mainTrackRanges, migrateLegacyTimelineToEntities, partDurationMs, partUnionSchema, phoneticScriptAssetContent, phoneticScriptAssetHash, phoneticScriptAssetOf, prepareCaptionAssetsEffect, prepareCaptionContent, prepareContinueVideoEffect, prepareGeneratedVisualEffect, prepareSpeechAssetsEffect, projectEntityTimeline, readDocumentAudioScript, readEntityDocument, readMainTrackItems, readMengineEventStream, readPart, readPartDurationMs, readVideoDocumentFromDraft, reassignSpeechesToVideoClipsByTime, recalculateTimelineDuration, relativePositionForAbs, replayJournal, resolveAllSpeechOverlaps, resolveEntityTimelineLayout, resolveFieldPath, resolveSpeechOverlapByShiftingVideos, safeDurationMs, index_d_exports as schemas, scriptSourceAssetOf, selectAudioScriptSegment, snapshotToPlain, solveVideoDocument, speedOf, syncAggregatedClipsTimePosition, toVideoDocument, validateVideoDocument, videoDocumentMirrorSchema, videoDocumentSchema };
|