@mengine/medeo-client 2.1.0 → 2.1.1-dsl.0
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 +126 -25
- package/dist/base64-D-jd-dr5.js +16 -0
- package/dist/dsl-Dkecq_2c.js +2814 -0
- package/dist/dsl.d.ts +3 -0
- package/dist/dsl.js +3 -0
- package/dist/index-B7fC7q7P.d.ts +728 -0
- package/dist/index-DKDMTXUe.d.ts +605 -0
- package/dist/index-DQZUkrpg.d.ts +197 -0
- package/dist/index.d.ts +5 -1141
- package/dist/index.js +109 -2606
- package/dist/legacy.d.ts +1044 -0
- package/dist/legacy.js +4349 -0
- package/dist/{loro-relay-doc-cJSY-uau.js → loro-relay-doc-Bi6JKqtQ.js} +11 -7
- package/dist/relay.js +1 -1
- package/dist/schemas.d.ts +606 -0
- package/dist/schemas.js +442 -0
- package/dist/shared-iWnU2osE.js +39 -0
- package/dist/storage-BW3tI_ER.js +801 -0
- package/dist/testing.d.ts +22 -9
- package/dist/testing.js +168 -50
- package/dist/video-draft-types-DTXxvPt-.js +449 -0
- package/dist/video-draft-types-c_shaRyq.d.ts +809 -0
- package/package.json +13 -6
- package/dist/chunk-D7D4PA-g.js +0 -13
- package/dist/document-B_JQwrC5.js +0 -1630
- package/dist/index-CnZ9l3rb.d.ts +0 -2077
package/dist/legacy.d.ts
ADDED
|
@@ -0,0 +1,1044 @@
|
|
|
1
|
+
import { i as VideoDraft, l as VideoDraftPartUnion, o as VideoDraftContent, p as CommitOptions, t as CaptionDisplayCue } from "./video-draft-types-c_shaRyq.js";
|
|
2
|
+
import { A as MengineAuditResponse, B as base64ToBytes, C as MengineEventStreamOptions, D as MengineHttpRequestError, E as MengineHttpClientOptions, F as MengineRejectedResponse, I as MengineSnapshotResponse, L as MengineSseUpdateEvent, M as MengineDraftResponse, N as MenginePushResponse, O as MenginePushRejectedError, P as MenginePushUpdateResponse, R as MengineSyncResponse, S as PushResultKind, T as MengineHttpClient, V as bytesToBase64, _ as encodeDocVersionMark, a as MengineDocSessionOptions, b as PullResult, c as DocStorageLike, d as MedeoHttpDocStorageOptions, f as PushOutcome, g as decodeDocVersionMark, h as ManualSyncTransport, j as MengineDocumentVersion, k as MengineAuditEntry, l as MengineUndoState, m as ManualSyncDocOptions, o as MengineDocSyncState, p as PushOutcomeKind, s as WaitForServerAckOptions, t as MemoryDocStorage, u as MedeoHttpDocStorage, v as DocVersionMark, w as readMengineEventStream, x as PushResult, y as PullFailureReason, z as MengineUpdateMeta } from "./index-B7fC7q7P.js";
|
|
3
|
+
import { LoroDoc, PeerID } from "loro-crdt";
|
|
4
|
+
|
|
5
|
+
//#region ../medeo-dsl/depreacted/sandbox.d.ts
|
|
6
|
+
/** Kinds a script can author. */
|
|
7
|
+
type EntityKind = 'timeline' | 'track' | 'clip' | 'sequence-marker' | 'video' | 'audio' | 'voiceover-recording' | 'image' | 'voice' | 'audio-script' | 'phonetic-script' | 'caption' | 'asset';
|
|
8
|
+
type RelationKind = 'contain' | 'marker' | 'clip-anchor' | 'voice-timbre' | 'caption-alignment' | 'derived-from' | 'from-asset' | 'to-asset';
|
|
9
|
+
/** One segment of an AudioScript, identified by a stable id rather than its ordinal. */
|
|
10
|
+
interface Segment {
|
|
11
|
+
segmentId: string;
|
|
12
|
+
}
|
|
13
|
+
interface ScriptSegment extends Segment {
|
|
14
|
+
text: string;
|
|
15
|
+
language?: string;
|
|
16
|
+
}
|
|
17
|
+
interface SegmentTime extends Segment {
|
|
18
|
+
startMs: number;
|
|
19
|
+
endMs: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Sequence: content that can be placed on a Track. It always has a length;
|
|
23
|
+
* `null` means infinite.
|
|
24
|
+
*/
|
|
25
|
+
interface Sequence {
|
|
26
|
+
durationMs: number | null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A variant names its bases; every field it does not state reads through to
|
|
30
|
+
* the base that has it, and membership is unordered. Any kind but an Asset may
|
|
31
|
+
* be a variant; a PhoneticScript and a Caption always are.
|
|
32
|
+
*/
|
|
33
|
+
interface Composed {
|
|
34
|
+
bases: string[];
|
|
35
|
+
}
|
|
36
|
+
/** Every style field a Caption may own; anything else is refused. */
|
|
37
|
+
interface CaptionStyle {
|
|
38
|
+
font?: {
|
|
39
|
+
system: 'font-library';
|
|
40
|
+
key: string;
|
|
41
|
+
};
|
|
42
|
+
fontSize?: number;
|
|
43
|
+
fontColor?: string;
|
|
44
|
+
fontWeight?: number;
|
|
45
|
+
entranceAnimation?: string;
|
|
46
|
+
entranceAnimationDurationMs?: number;
|
|
47
|
+
strokeColor?: string;
|
|
48
|
+
strokeWidth?: number;
|
|
49
|
+
positionX?: number;
|
|
50
|
+
positionY?: number;
|
|
51
|
+
}
|
|
52
|
+
/** A kind, or a relation, with no fields of its own. */
|
|
53
|
+
type Empty = Record<never, never>;
|
|
54
|
+
/** Own fields by kind. A kind states these and nothing else. */
|
|
55
|
+
interface Payload {
|
|
56
|
+
/** Structure only: its Tracks are its content. */
|
|
57
|
+
timeline: Empty;
|
|
58
|
+
/** What the Track is for; the roles a document starts with come with its snapshot. */
|
|
59
|
+
track: {
|
|
60
|
+
role: string;
|
|
61
|
+
hidden?: boolean;
|
|
62
|
+
};
|
|
63
|
+
/** Where it sits in its Track is the order of its contain Relation; a Marker startMs overrides where it begins. volume is decibels, -60 to 20, 0 the source's own level. */
|
|
64
|
+
clip: {
|
|
65
|
+
volume?: number;
|
|
66
|
+
};
|
|
67
|
+
'sequence-marker': {
|
|
68
|
+
/** In point on the source, from 0. */inMs: number; /** Out point on the source. outMs - inMs is how long this content runs. */
|
|
69
|
+
outMs: number; /** Where the Clip begins, overriding its order: on the Track, or inside the Clip named by clip-anchor. */
|
|
70
|
+
startMs?: number; /** Linear speed; omitted means 1. Played length is (outMs - inMs) / rate. Video and audio only. */
|
|
71
|
+
rate?: number; /** BGM only: run as long as the Timeline instead of the source. */
|
|
72
|
+
fillTimeline?: true; /** Assigned AudioScript times, counted from the annotated audio's start; annotation Markers only. */
|
|
73
|
+
segmentRanges?: SegmentTime[];
|
|
74
|
+
};
|
|
75
|
+
/** Media is made from stored bytes: link its Asset with from-asset. */
|
|
76
|
+
video: Sequence;
|
|
77
|
+
/** Sound that carries no language: BGM, sound effects, a video's own track. Spoken language is a voiceover-recording. */
|
|
78
|
+
audio: Sequence;
|
|
79
|
+
/** Speech. It states the PhoneticScript it was spoken from through derived-from. */
|
|
80
|
+
'voiceover-recording': Sequence;
|
|
81
|
+
image: Sequence;
|
|
82
|
+
/** A timbre identity, never playable; the take rendered with it is a voiceover-recording. */
|
|
83
|
+
voice: {
|
|
84
|
+
voice: {
|
|
85
|
+
system: 'voice-library';
|
|
86
|
+
key: string;
|
|
87
|
+
name?: string;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
/** A script written here owns its text; one read off media links the transcript it was read from with from-asset. */
|
|
91
|
+
'audio-script': {
|
|
92
|
+
segments: ScriptSegment[];
|
|
93
|
+
};
|
|
94
|
+
/** Pronunciation the plain script cannot state, in the target TTS vocabulary. */
|
|
95
|
+
'phonetic-script': Composed & {
|
|
96
|
+
phonemeScript?: string;
|
|
97
|
+
};
|
|
98
|
+
caption: Sequence & Composed & {
|
|
99
|
+
/** One script segment, or a half-open code-point range inside it. */selection: Segment & {
|
|
100
|
+
textRange?: {
|
|
101
|
+
start: number;
|
|
102
|
+
end: number;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
style?: CaptionStyle;
|
|
106
|
+
segmentRanges?: SegmentTime[];
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Stored bytes. A document holds one Asset per system and key: reuse the one
|
|
110
|
+
* it has. Every field but system and key is a fact the host records.
|
|
111
|
+
*/
|
|
112
|
+
asset: {
|
|
113
|
+
/** Speech results (ids starting `sph_`) are memota-speech; every other resource is memota. */system: 'memota' | 'memota-speech'; /** The bytes' id in that store. */
|
|
114
|
+
key: string; /** Where the bytes live in storage. */
|
|
115
|
+
storageKey?: string; /** Fingerprint of the bytes. */
|
|
116
|
+
digest?: string;
|
|
117
|
+
/**
|
|
118
|
+
* The bytes are this document's own content written out, so it may write
|
|
119
|
+
* them again: their digest is one it can work out from that content at any
|
|
120
|
+
* time, which is how it sees that the content has moved past them. Bytes a
|
|
121
|
+
* store produced state nothing here and are never written again.
|
|
122
|
+
*/
|
|
123
|
+
writable?: true;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** Stated in full, or stated by a variant over its bases. An Asset is the bytes themselves and has no variant. */
|
|
127
|
+
type StoredPayload<K extends EntityKind> = Payload[K] | (K extends 'asset' ? never : Partial<Payload[K]> & Composed);
|
|
128
|
+
//#endregion
|
|
129
|
+
//#region ../medeo-dsl/depreacted/src/ids.d.ts
|
|
130
|
+
declare const entityIdBrand: unique symbol;
|
|
131
|
+
declare const relationIdBrand: unique symbol;
|
|
132
|
+
type EntityId = string & {
|
|
133
|
+
readonly [entityIdBrand]: 'EntityId';
|
|
134
|
+
};
|
|
135
|
+
type RelationId = string & {
|
|
136
|
+
readonly [relationIdBrand]: 'RelationId';
|
|
137
|
+
};
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region ../medeo-dsl/depreacted/src/entities/types.d.ts
|
|
140
|
+
/** One independently identified Medeo domain object. Peer associations belong in Relation rows. */
|
|
141
|
+
interface MedeoEntity<K extends EntityKind = EntityKind> {
|
|
142
|
+
readonly entityId: EntityId;
|
|
143
|
+
readonly entityKind: K;
|
|
144
|
+
}
|
|
145
|
+
type Of<K extends EntityKind> = MedeoEntity<K> & Readonly<Payload[K]>;
|
|
146
|
+
type Voice = Of<'voice'>;
|
|
147
|
+
type Caption = Of<'caption'>;
|
|
148
|
+
/** One persisted entity: its identity, its kind, and the fields its row states — in full, or as a variant. */
|
|
149
|
+
type EntityRow<K extends EntityKind = EntityKind> = { [P in K]: {
|
|
150
|
+
readonly entityId: EntityId;
|
|
151
|
+
readonly entityKind: P;
|
|
152
|
+
readonly payload: Readonly<StoredPayload<P>>;
|
|
153
|
+
} }[K];
|
|
154
|
+
/**
|
|
155
|
+
* An entity read through its bases: every field its kind has, wherever it is
|
|
156
|
+
* stated. A document that compiled reads this way; so does any row stating
|
|
157
|
+
* all it has.
|
|
158
|
+
*/
|
|
159
|
+
type AssembledRow<K extends EntityKind = EntityKind> = { [P in K]: {
|
|
160
|
+
readonly entityId: EntityId;
|
|
161
|
+
readonly entityKind: P;
|
|
162
|
+
readonly payload: Readonly<Payload[P]>;
|
|
163
|
+
} }[K];
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region ../medeo-dsl/depreacted/src/relations/types.d.ts
|
|
166
|
+
/**
|
|
167
|
+
* Authoritative persisted relation value. Every kind gives endpoint 0 and
|
|
168
|
+
* endpoint 1 their own roles, so the positions a row states are kept as given.
|
|
169
|
+
*/
|
|
170
|
+
interface RelationRow<K extends RelationKind = RelationKind> {
|
|
171
|
+
readonly relationId: RelationId;
|
|
172
|
+
readonly endpoint0EntityId: EntityId;
|
|
173
|
+
readonly endpoint1EntityId: EntityId;
|
|
174
|
+
readonly relationKind: K;
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region ../medeo-dsl/depreacted/src/compile.d.ts
|
|
178
|
+
/** A document's stored rows: every entity and every relation. This is what compiles. */
|
|
179
|
+
interface EntityRelationRows {
|
|
180
|
+
readonly entities: readonly EntityRow[];
|
|
181
|
+
readonly relations: readonly RelationRow[];
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region ../medeo-dsl/depreacted/src/entities/runtime.d.ts
|
|
185
|
+
type ScriptCompositionIssueCode = 'field_conflict' | 'composition_cycle' | 'invalid_bases' | 'composition_dangling' | 'unknown_segment' | 'empty_selection' | 'invalid_script' | 'invalid_selection';
|
|
186
|
+
declare class ScriptCompositionError extends Error {
|
|
187
|
+
readonly code: ScriptCompositionIssueCode;
|
|
188
|
+
readonly entityId: EntityId;
|
|
189
|
+
constructor(code: ScriptCompositionIssueCode, entityId: EntityId, message: string);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* An entity read through its `bases`: an own field wins, otherwise the field
|
|
193
|
+
* comes from the base that has it, however deep.
|
|
194
|
+
*
|
|
195
|
+
* The payload is a live, read-only view. Reads follow edits to any base; writes
|
|
196
|
+
* are refused, and go through `updateEntityFields`, which finds the entity that
|
|
197
|
+
* actually owns the field.
|
|
198
|
+
*
|
|
199
|
+
* Reading never judges the composition. Missing bases, cycles and two bases
|
|
200
|
+
* supplying one field are compile errors, reported by `checkComposition`; on
|
|
201
|
+
* uncompiled rows a read skips what it cannot reach and takes the first base
|
|
202
|
+
* that has the field.
|
|
203
|
+
*
|
|
204
|
+
* Naming the kind the caller expects narrows the row to that kind's fields.
|
|
205
|
+
*/
|
|
206
|
+
declare function assembleEntityContent<K extends EntityKind = EntityKind>(rows: EntityRelationRows, entityId: EntityId, kind?: K): AssembledRow<K>;
|
|
207
|
+
/** The entity whose own payload holds `field` for this entity — itself or a base — or undefined when none does. */
|
|
208
|
+
declare function resolveEntityFieldOwner(rows: EntityRelationRows, entityId: EntityId, field: string): EntityId | undefined;
|
|
209
|
+
/** The whole text a row carries — its own segments or those it reads through its bases — in segment order. */
|
|
210
|
+
declare function assembleScriptText(row: EntityRow): string;
|
|
211
|
+
/** A row's segments, own or composed; pass an assembled row to read through its bases. */
|
|
212
|
+
declare function segmentsOf(row: EntityRow): readonly ScriptSegment[];
|
|
213
|
+
/**
|
|
214
|
+
* The text a Caption shows: the segment its `selection` names, among the
|
|
215
|
+
* segments it reads through its bases, narrowed by `textRange`. Pass the
|
|
216
|
+
* assembled Caption; a stored Caption holds no segments of its own.
|
|
217
|
+
*/
|
|
218
|
+
declare function selectedSegment(caption: EntityRow): ScriptSegment;
|
|
219
|
+
//#endregion
|
|
220
|
+
//#region src/legacy/projection/entity-projection-values.d.ts
|
|
221
|
+
/** A graph cannot be represented faithfully by the compatibility reader. */
|
|
222
|
+
declare class EntityTimelineProjectionError extends Error {
|
|
223
|
+
constructor(message: string);
|
|
224
|
+
}
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/legacy/projection/entity-projection.d.ts
|
|
227
|
+
/**
|
|
228
|
+
* One-way compatibility view over the Entity graph. A legacy part is never
|
|
229
|
+
* consulted as an editing fact. Peer IDs appear only in this derived read
|
|
230
|
+
* contract, reconstructed from relations; they are not stored in payloads.
|
|
231
|
+
*/
|
|
232
|
+
declare function projectEntityTimeline(rows: EntityRelationRows): VideoDraftContent;
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/legacy/projection/entity-timeline-layout.d.ts
|
|
235
|
+
type EntityTimelineTrackRole = 'video_clip' | 'speech' | 'caption' | 'bgm';
|
|
236
|
+
interface ResolvedEntityClipPlacement {
|
|
237
|
+
readonly clipEntityId: string;
|
|
238
|
+
readonly markerEntityId: string;
|
|
239
|
+
readonly contentEntityId: string;
|
|
240
|
+
readonly trackEntityId: string;
|
|
241
|
+
readonly start: number;
|
|
242
|
+
readonly duration: number;
|
|
243
|
+
readonly mode: 'sequential' | 'absolute' | 'anchored';
|
|
244
|
+
readonly anchorClipEntityId?: string;
|
|
245
|
+
readonly anchorOffset?: number;
|
|
246
|
+
}
|
|
247
|
+
interface ResolvedEntityTrack {
|
|
248
|
+
readonly entityId: string;
|
|
249
|
+
readonly role: EntityTimelineTrackRole;
|
|
250
|
+
readonly order: number;
|
|
251
|
+
readonly hidden: boolean;
|
|
252
|
+
readonly clips: readonly ResolvedEntityClipPlacement[];
|
|
253
|
+
}
|
|
254
|
+
interface ResolvedEntityTimelineLayout {
|
|
255
|
+
readonly tracks: readonly ResolvedEntityTrack[];
|
|
256
|
+
readonly clips: ReadonlyMap<string, ResolvedEntityClipPlacement>;
|
|
257
|
+
/** Background music fills this duration; it never extends the timeline. */
|
|
258
|
+
readonly durationMs: number;
|
|
259
|
+
}
|
|
260
|
+
/** Validated graph lookup shared by the compatibility layout and projection. */
|
|
261
|
+
declare class EntityProjectionGraph {
|
|
262
|
+
readonly rows: EntityRelationRows;
|
|
263
|
+
readonly entities: ReadonlyMap<string, AssembledRow>;
|
|
264
|
+
readonly timeline: AssembledRow<'timeline'>;
|
|
265
|
+
constructor(rows: EntityRelationRows);
|
|
266
|
+
/** The entity with this id; naming its kind narrows the row to that kind's fields. */
|
|
267
|
+
entity<K extends EntityKind = EntityKind>(id: string, kind?: K): AssembledRow<K>;
|
|
268
|
+
adjacent(id: string, kind: RelationKind): AssembledRow[];
|
|
269
|
+
/** What this entity contains, as opposed to what contains it. */
|
|
270
|
+
holds(id: string): AssembledRow[];
|
|
271
|
+
heldBy(id: string): AssembledRow[];
|
|
272
|
+
/**
|
|
273
|
+
* Ordered relations put the product at endpoint 0 and its source at endpoint 1.
|
|
274
|
+
* One entity can sit on both sides of the same kind — a Voiceover Recording is
|
|
275
|
+
* spoken from a PhoneticScript and is itself what a transcript was read from —
|
|
276
|
+
* so provenance is never read through the undirected `adjacent`.
|
|
277
|
+
*/
|
|
278
|
+
madeFrom(id: string, kind: RelationKind): AssembledRow[];
|
|
279
|
+
madeInto(id: string, kind: RelationKind): AssembledRow[];
|
|
280
|
+
one<K extends EntityKind = EntityKind>(id: string, relation: RelationKind, kind?: K, values?: AssembledRow[]): AssembledRow<K>;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Resolve only entity-owned placement facts. This does not choose new anchors,
|
|
284
|
+
* manufacture clips, or mutate a graph while reading. Write-side operations
|
|
285
|
+
* must express any detach/reparent/overlap decision in their entity plan.
|
|
286
|
+
*/
|
|
287
|
+
declare function resolveEntityTimelineLayout(rows: EntityRelationRows): ResolvedEntityTimelineLayout;
|
|
288
|
+
declare function resolveGraphLayout(graph: EntityProjectionGraph): ResolvedEntityTimelineLayout;
|
|
289
|
+
//#endregion
|
|
290
|
+
//#region src/entity-editor/entity-graph-http-client.d.ts
|
|
291
|
+
/** One authenticated revision of the authoritative Medeo Entity graph. */
|
|
292
|
+
interface EntityGraphState {
|
|
293
|
+
/** Current AudioScript attached to the project, or null until one is written. */
|
|
294
|
+
readonly audioScriptEntityId: string | null;
|
|
295
|
+
readonly revision: number;
|
|
296
|
+
readonly loroSnapshot: string;
|
|
297
|
+
readonly rows: EntityRelationRows;
|
|
298
|
+
}
|
|
299
|
+
interface EntityGraphCommitOptions {
|
|
300
|
+
/** Server version vector proving the explicit legacy-to-Entity migration baseline. */
|
|
301
|
+
readonly migrationBaseVv?: string;
|
|
302
|
+
}
|
|
303
|
+
/** Browser-safe authenticated Loro client for a document's Entity graph. */
|
|
304
|
+
declare class EntityGraphHttpClient {
|
|
305
|
+
private readonly options;
|
|
306
|
+
private readonly transport;
|
|
307
|
+
private readonly endpoint;
|
|
308
|
+
constructor(options: MengineHttpClientOptions);
|
|
309
|
+
fetchState(): Promise<EntityGraphState>;
|
|
310
|
+
/**
|
|
311
|
+
* Apply edits against the original causal snapshot and publish native Loro operations.
|
|
312
|
+
*
|
|
313
|
+
* Deletion intent is derived from baseline IDs omitted from `nextRows`, so a
|
|
314
|
+
* transient create-then-remove never becomes a request to delete unknown
|
|
315
|
+
* persisted data.
|
|
316
|
+
*/
|
|
317
|
+
commit(baseState: Pick<EntityGraphState, 'revision' | 'rows' | 'loroSnapshot'>, nextRows: EntityRelationRows, options?: EntityGraphCommitOptions): Promise<EntityGraphState>;
|
|
318
|
+
/** Send the same prepared bytes on retry; never re-apply an unconfirmed edit. */
|
|
319
|
+
commitUpdate(update: string): Promise<EntityGraphState>;
|
|
320
|
+
private request;
|
|
321
|
+
}
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region src/entity-editor/types.d.ts
|
|
324
|
+
/** Injectable domain-id mint shared by Entity and Relation authoring surfaces. */
|
|
325
|
+
type EntityTimelineIdFactory = (prefix: 'entity' | 'relation') => string;
|
|
326
|
+
interface ImageMediaAssetFact {
|
|
327
|
+
readonly assetId: string;
|
|
328
|
+
readonly kind: 'image';
|
|
329
|
+
readonly durationMs: number | null;
|
|
330
|
+
readonly storageKey?: string;
|
|
331
|
+
}
|
|
332
|
+
interface VideoMediaAssetFact {
|
|
333
|
+
readonly assetId: string;
|
|
334
|
+
readonly kind: 'video';
|
|
335
|
+
readonly durationMs: number | null;
|
|
336
|
+
readonly storageKey?: string;
|
|
337
|
+
}
|
|
338
|
+
interface AudioMediaAssetFact {
|
|
339
|
+
readonly assetId: string;
|
|
340
|
+
readonly kind: 'audio';
|
|
341
|
+
readonly durationMs: number | null;
|
|
342
|
+
readonly storageKey: string;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Speech. It materializes as a `voiceover` entity — its own kind, because only
|
|
346
|
+
* speech answers which words it said; `voice` names the timbre identity it was
|
|
347
|
+
* synthesized with, which becomes its own Voice entity linked by a
|
|
348
|
+
* `voice-timbre` Relation.
|
|
349
|
+
*/
|
|
350
|
+
interface VoiceoverMediaAssetFact {
|
|
351
|
+
/** Stable external speech result id, independent of the placed Clip id. */
|
|
352
|
+
readonly assetId: string;
|
|
353
|
+
readonly kind: 'voiceover-recording';
|
|
354
|
+
readonly durationMs: number | null;
|
|
355
|
+
readonly storageKey: string;
|
|
356
|
+
/**
|
|
357
|
+
* The PhoneticScript this take was spoken from, when the caller minting it
|
|
358
|
+
* knows. A migration that rebuilds the whole chain relates it itself; either
|
|
359
|
+
* way a take that never names one is refused when a plan is built.
|
|
360
|
+
*/
|
|
361
|
+
readonly phoneticScriptEntityId?: string;
|
|
362
|
+
/** Present for synthesized speech, absent for original recorded audio. */
|
|
363
|
+
readonly voice?: Voice['voice'];
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Facts resolved from media storage. Every medium states its length: whole
|
|
367
|
+
* milliseconds, or `null` for infinite. A trim window never substitutes for it.
|
|
368
|
+
*/
|
|
369
|
+
type MediaAssetFact = ImageMediaAssetFact | VideoMediaAssetFact | AudioMediaAssetFact | VoiceoverMediaAssetFact;
|
|
370
|
+
/** Where a Clip starts: in flow by order, or at a stated start on its Track or inside its host. */
|
|
371
|
+
type ClipPlacement = {
|
|
372
|
+
readonly kind: 'sequential';
|
|
373
|
+
readonly order: number;
|
|
374
|
+
} | {
|
|
375
|
+
readonly kind: 'absolute';
|
|
376
|
+
readonly startMs: number;
|
|
377
|
+
} | {
|
|
378
|
+
readonly kind: 'anchored';
|
|
379
|
+
readonly hostClipEntityId: string;
|
|
380
|
+
readonly startMs: number;
|
|
381
|
+
};
|
|
382
|
+
interface InsertPlacedClipInput {
|
|
383
|
+
readonly trackEntityId: string;
|
|
384
|
+
readonly contentEntityId: string;
|
|
385
|
+
readonly inMs: number;
|
|
386
|
+
readonly outMs: number;
|
|
387
|
+
readonly placement: ClipPlacement;
|
|
388
|
+
readonly clipPayload?: Payload['clip'];
|
|
389
|
+
/** Stable caller-owned placement identity, when one already exists outside the graph. */
|
|
390
|
+
readonly clipEntityId?: string;
|
|
391
|
+
}
|
|
392
|
+
interface SetClipPlacementInput {
|
|
393
|
+
readonly clipEntityId: string;
|
|
394
|
+
readonly placement: ClipPlacement;
|
|
395
|
+
}
|
|
396
|
+
type SequentialClipAnchor = {
|
|
397
|
+
readonly position: 'before' | 'after';
|
|
398
|
+
readonly clipEntityId: string;
|
|
399
|
+
} | {
|
|
400
|
+
readonly position: 'trackStart';
|
|
401
|
+
};
|
|
402
|
+
interface MoveSequentialClipsInput {
|
|
403
|
+
readonly clipEntityIds: readonly string[];
|
|
404
|
+
readonly anchor: SequentialClipAnchor;
|
|
405
|
+
readonly onAnchored: 'follow' | 'keepAbsolute';
|
|
406
|
+
}
|
|
407
|
+
interface MoveClipsToStartsInput {
|
|
408
|
+
readonly moves: readonly {
|
|
409
|
+
readonly clipEntityId: string;
|
|
410
|
+
readonly newStartMs: number;
|
|
411
|
+
}[];
|
|
412
|
+
/** Absolute-time drags preserve every voiceover's current visible landing. */
|
|
413
|
+
readonly onAnchored: 'keepAbsolute';
|
|
414
|
+
}
|
|
415
|
+
interface DeleteClipTreeInput {
|
|
416
|
+
readonly clipEntityIds: readonly string[];
|
|
417
|
+
readonly onAnchored: 'cascade' | 'detach';
|
|
418
|
+
}
|
|
419
|
+
interface VoiceoverCaptionFact {
|
|
420
|
+
/** Stable placed caption identity supplied by the materialized side effect. */
|
|
421
|
+
readonly captionClipEntityId: string;
|
|
422
|
+
/** Directly held bases; includes the AudioScript the voiceover was rendered from. */
|
|
423
|
+
readonly bases: readonly string[];
|
|
424
|
+
/** Ordered selection of AudioScript segments; caption text is never passed inline. */
|
|
425
|
+
readonly selection: Caption['selection'];
|
|
426
|
+
readonly startMs: number;
|
|
427
|
+
readonly durationMs: number;
|
|
428
|
+
readonly style?: CaptionStyle;
|
|
429
|
+
}
|
|
430
|
+
type VoiceoverTakeInput = {
|
|
431
|
+
readonly timelineEntityId: string; /** Stable placed speech identity, distinct from media.assetId. */
|
|
432
|
+
readonly voiceoverClipEntityId: string;
|
|
433
|
+
readonly media: VoiceoverMediaAssetFact; /** Existing pronunciation variant; its composed AudioScript stays the text owner. */
|
|
434
|
+
readonly phoneticScriptEntityId: string;
|
|
435
|
+
readonly volume: number;
|
|
436
|
+
readonly captions: readonly VoiceoverCaptionFact[];
|
|
437
|
+
} & ({
|
|
438
|
+
readonly placement: ClipPlacement;
|
|
439
|
+
readonly hostClipEntityId?: never;
|
|
440
|
+
readonly startMs?: never;
|
|
441
|
+
} | {
|
|
442
|
+
readonly placement?: never;
|
|
443
|
+
readonly hostClipEntityId: string;
|
|
444
|
+
readonly startMs: number;
|
|
445
|
+
});
|
|
446
|
+
type VisualMediaAssetFact = ImageMediaAssetFact | VideoMediaAssetFact;
|
|
447
|
+
interface InsertMediaClipInput {
|
|
448
|
+
readonly timelineEntityId: string;
|
|
449
|
+
readonly clipEntityId?: string;
|
|
450
|
+
readonly media: VisualMediaAssetFact;
|
|
451
|
+
/** Window on the source, whole milliseconds. An Image uses it as its finite display span. */
|
|
452
|
+
readonly inMs: number;
|
|
453
|
+
readonly outMs: number;
|
|
454
|
+
readonly placement: ClipPlacement;
|
|
455
|
+
readonly volume?: number;
|
|
456
|
+
}
|
|
457
|
+
interface ReplaceMediaClipInput {
|
|
458
|
+
readonly clipEntityId: string;
|
|
459
|
+
readonly media: VisualMediaAssetFact;
|
|
460
|
+
readonly inMs: number;
|
|
461
|
+
readonly outMs: number;
|
|
462
|
+
}
|
|
463
|
+
interface ReplacementMediaClipInput {
|
|
464
|
+
readonly clipEntityId?: string;
|
|
465
|
+
readonly media: VisualMediaAssetFact;
|
|
466
|
+
readonly inMs: number;
|
|
467
|
+
readonly outMs: number;
|
|
468
|
+
readonly volume?: number;
|
|
469
|
+
}
|
|
470
|
+
type MediaClipInsertion = {
|
|
471
|
+
readonly kind: 'before';
|
|
472
|
+
readonly clipEntityId: string;
|
|
473
|
+
} | {
|
|
474
|
+
readonly kind: 'after';
|
|
475
|
+
readonly clipEntityId: string;
|
|
476
|
+
} | {
|
|
477
|
+
readonly kind: 'firstStart';
|
|
478
|
+
readonly startMs: number;
|
|
479
|
+
};
|
|
480
|
+
interface InsertMediaClipsInput {
|
|
481
|
+
readonly timelineEntityId: string;
|
|
482
|
+
readonly clips: readonly ReplacementMediaClipInput[];
|
|
483
|
+
/** One placement decision for the whole input-ordered block. */
|
|
484
|
+
readonly insertion: MediaClipInsertion;
|
|
485
|
+
}
|
|
486
|
+
interface ReplaceSequentialClipsInput {
|
|
487
|
+
readonly timelineEntityId: string;
|
|
488
|
+
readonly oldClipEntityIds: readonly string[];
|
|
489
|
+
readonly newClips: readonly ReplacementMediaClipInput[];
|
|
490
|
+
readonly onAnchored: 'remap' | 'cascade';
|
|
491
|
+
}
|
|
492
|
+
interface SetClipVolumeInput {
|
|
493
|
+
readonly clipEntityId: string;
|
|
494
|
+
/** Playback gain in decibels. */
|
|
495
|
+
readonly volume: number;
|
|
496
|
+
}
|
|
497
|
+
interface LinearClipSpeed {
|
|
498
|
+
readonly kind: 'linear';
|
|
499
|
+
readonly rate: number;
|
|
500
|
+
readonly mode?: string;
|
|
501
|
+
}
|
|
502
|
+
interface SetClipSpeedInput {
|
|
503
|
+
readonly clipEntityId: string;
|
|
504
|
+
/** Linear speed; null restores the source's own pace. */
|
|
505
|
+
readonly rate: number | null;
|
|
506
|
+
}
|
|
507
|
+
interface TrimClipInput {
|
|
508
|
+
readonly clipEntityId: string;
|
|
509
|
+
readonly inMs: number;
|
|
510
|
+
readonly outMs: number;
|
|
511
|
+
}
|
|
512
|
+
interface VoiceoverTakeResult {
|
|
513
|
+
readonly voiceoverClipEntityId: string;
|
|
514
|
+
/** The rendered voiceover Audio entity. */
|
|
515
|
+
readonly voiceoverAudioEntityId: string;
|
|
516
|
+
/** The timbre identity it was synthesized with, when the take declared one. */
|
|
517
|
+
readonly voiceEntityId?: string;
|
|
518
|
+
/** The pronunciation variant the voiceover was rendered from. */
|
|
519
|
+
readonly phoneticScriptEntityId: string;
|
|
520
|
+
/** The base-text owner resolved from the PhoneticScript bases. */
|
|
521
|
+
readonly audioScriptEntityId: string;
|
|
522
|
+
readonly captionClipEntityIds: readonly string[];
|
|
523
|
+
}
|
|
524
|
+
interface MoveVoiceoverInput {
|
|
525
|
+
readonly voiceoverClipEntityId: string;
|
|
526
|
+
/** Absolute requested timeline start; MEngine resolves and persists the host relation. */
|
|
527
|
+
readonly newStartMs: number;
|
|
528
|
+
}
|
|
529
|
+
interface DeleteVoiceoverInput {
|
|
530
|
+
readonly voiceoverClipEntityIds: readonly string[];
|
|
531
|
+
}
|
|
532
|
+
interface SetBgmInput {
|
|
533
|
+
readonly timelineEntityId: string;
|
|
534
|
+
readonly bgmClipEntityId: string;
|
|
535
|
+
readonly media: AudioMediaAssetFact;
|
|
536
|
+
readonly volume: number;
|
|
537
|
+
}
|
|
538
|
+
interface DeleteBgmInput {
|
|
539
|
+
readonly timelineEntityId: string;
|
|
540
|
+
}
|
|
541
|
+
interface SetCaptionVisibilityInput {
|
|
542
|
+
readonly timelineEntityId: string;
|
|
543
|
+
readonly hidden: boolean;
|
|
544
|
+
}
|
|
545
|
+
interface PatchCaptionStyleInput {
|
|
546
|
+
readonly timelineEntityId: string;
|
|
547
|
+
readonly style: CaptionStyle;
|
|
548
|
+
}
|
|
549
|
+
interface InsertCaptionClipInput {
|
|
550
|
+
readonly timelineEntityId: string;
|
|
551
|
+
/** Existing generation identity for newly materialized Caption content, distinct from its Clip. */
|
|
552
|
+
readonly captionEntityId?: string;
|
|
553
|
+
/** Stable placed caption identity, distinct from the Caption content identity. */
|
|
554
|
+
readonly captionClipEntityId?: string;
|
|
555
|
+
/** Existing bases composed by this variant; includes an AudioScript text owner. */
|
|
556
|
+
readonly bases: readonly string[];
|
|
557
|
+
/** Ordered selection of the AudioScript segments this Caption displays. */
|
|
558
|
+
readonly selection: Caption['selection'];
|
|
559
|
+
/** Intrinsic cue length of the Caption entity itself; display comes from the placement. */
|
|
560
|
+
readonly durationMs: number;
|
|
561
|
+
readonly style?: CaptionStyle;
|
|
562
|
+
readonly placement: ClipPlacement;
|
|
563
|
+
}
|
|
564
|
+
interface InsertClipInput {
|
|
565
|
+
readonly trackEntityId: string;
|
|
566
|
+
/** Existing Sequence media Entity id. Asset ids and URLs are not content ids. */
|
|
567
|
+
readonly contentEntityId: string;
|
|
568
|
+
readonly inMs: number;
|
|
569
|
+
readonly outMs: number;
|
|
570
|
+
readonly startMs?: number;
|
|
571
|
+
/** Where among its Track's Clips it lands; appended when omitted. */
|
|
572
|
+
readonly order?: number;
|
|
573
|
+
readonly clipPayload?: Payload['clip'];
|
|
574
|
+
}
|
|
575
|
+
interface UpdateClipMarkerInput {
|
|
576
|
+
readonly clipEntityId: string;
|
|
577
|
+
readonly inMs?: number;
|
|
578
|
+
readonly outMs?: number;
|
|
579
|
+
/** Passing `undefined` explicitly removes the optional start. */
|
|
580
|
+
readonly startMs?: number | undefined;
|
|
581
|
+
/** Passing `undefined` explicitly removes the optional rate. */
|
|
582
|
+
readonly rate?: number | undefined;
|
|
583
|
+
}
|
|
584
|
+
interface MoveClipInput {
|
|
585
|
+
readonly clipEntityId: string;
|
|
586
|
+
readonly trackEntityId: string;
|
|
587
|
+
}
|
|
588
|
+
interface ReplaceClipContentInput {
|
|
589
|
+
readonly clipEntityId: string;
|
|
590
|
+
/** Existing Sequence media Entity id. Asset ids and URLs are not content ids. */
|
|
591
|
+
readonly contentEntityId: string;
|
|
592
|
+
readonly inMs: number;
|
|
593
|
+
readonly outMs: number;
|
|
594
|
+
readonly startMs?: number;
|
|
595
|
+
readonly rate?: number;
|
|
596
|
+
}
|
|
597
|
+
interface DeleteClipInput {
|
|
598
|
+
readonly clipEntityId: string;
|
|
599
|
+
}
|
|
600
|
+
interface UpdateClipInput {
|
|
601
|
+
readonly clipEntityId: string;
|
|
602
|
+
/** Complete replacement for the Clip-owned payload. */
|
|
603
|
+
readonly payload: Payload['clip'];
|
|
604
|
+
}
|
|
605
|
+
type ClipEntityId = EntityId;
|
|
606
|
+
//#endregion
|
|
607
|
+
//#region src/entity-editor/entity-timeline-editor.d.ts
|
|
608
|
+
/**
|
|
609
|
+
* Graph-native timeline authoring over authoritative Medeo Entity and Relation rows.
|
|
610
|
+
*
|
|
611
|
+
* Each mutation is applied to a detached graph, validated as a complete DSL set,
|
|
612
|
+
* and committed only after validation succeeds.
|
|
613
|
+
*/
|
|
614
|
+
declare class EntityTimelineEditor {
|
|
615
|
+
private readonly idFactory;
|
|
616
|
+
private state;
|
|
617
|
+
constructor(initialRows: EntityRelationRows, idFactory?: EntityTimelineIdFactory);
|
|
618
|
+
rows(): EntityRelationRows;
|
|
619
|
+
insertClip(input: InsertClipInput): ClipEntityId;
|
|
620
|
+
insertPlacedClip(input: InsertPlacedClipInput): ClipEntityId;
|
|
621
|
+
updateClipMarker(input: UpdateClipMarkerInput): void;
|
|
622
|
+
setClipPlacement(input: SetClipPlacementInput): void;
|
|
623
|
+
moveSequentialClips(input: MoveSequentialClipsInput): void;
|
|
624
|
+
moveClipsToStarts(input: MoveClipsToStartsInput): void;
|
|
625
|
+
moveClip(input: MoveClipInput): void;
|
|
626
|
+
replaceClipContent(input: ReplaceClipContentInput): void;
|
|
627
|
+
insertMediaClip(input: InsertMediaClipInput): ClipEntityId;
|
|
628
|
+
insertMediaClips(input: InsertMediaClipsInput): readonly ClipEntityId[];
|
|
629
|
+
replaceMediaClip(input: ReplaceMediaClipInput): void;
|
|
630
|
+
setClipVolume(input: SetClipVolumeInput): void;
|
|
631
|
+
setClipSpeed(input: SetClipSpeedInput): void;
|
|
632
|
+
trimClip(input: TrimClipInput): void;
|
|
633
|
+
replaceSequentialClips(input: ReplaceSequentialClipsInput): readonly ClipEntityId[];
|
|
634
|
+
deleteClip(input: DeleteClipInput): void;
|
|
635
|
+
deleteClipTree(input: DeleteClipTreeInput): void;
|
|
636
|
+
updateClip(input: UpdateClipInput): void;
|
|
637
|
+
upsertVoiceoverTake(input: VoiceoverTakeInput): VoiceoverTakeResult;
|
|
638
|
+
moveVoiceover(input: MoveVoiceoverInput): void;
|
|
639
|
+
deleteVoiceover(input: DeleteVoiceoverInput): void;
|
|
640
|
+
setBgm(input: SetBgmInput): ClipEntityId;
|
|
641
|
+
deleteBgm(input: DeleteBgmInput): void;
|
|
642
|
+
setCaptionVisibility(input: SetCaptionVisibilityInput): void;
|
|
643
|
+
patchCaptionStyle(input: PatchCaptionStyleInput): void;
|
|
644
|
+
/**
|
|
645
|
+
* Place a Caption as a composed variant of an existing AudioScript: the
|
|
646
|
+
* entity stores bases, selection, optional style, and inherent cue-bounded
|
|
647
|
+
* Sequence. This helper does not copy base text. The Clip and its display Marker describe this use;
|
|
648
|
+
* moving or stretching the returned Clip later changes the Clip/Marker,
|
|
649
|
+
* never the Caption entity or the AudioScript.
|
|
650
|
+
*/
|
|
651
|
+
insertCaptionClip(input: InsertCaptionClipInput): ClipEntityId;
|
|
652
|
+
private insertPlacedClipIntoDraft;
|
|
653
|
+
private ensureRoleTrack;
|
|
654
|
+
/** The existing pronunciation variant a voiceover consumes; composition is required. */
|
|
655
|
+
private requireComposedPhoneticScript;
|
|
656
|
+
/** Preserve the factual synthesis input, regardless of persisted endpoint positions. */
|
|
657
|
+
private ensurePhoneticRender;
|
|
658
|
+
private reconcileVoiceoverCaptions;
|
|
659
|
+
private ensureRoleTrackForClip;
|
|
660
|
+
/** A Caption follows one take; it is relinked only when that take changes. */
|
|
661
|
+
private replaceCaptionAlignment;
|
|
662
|
+
/**
|
|
663
|
+
* Remove one placed Caption use. The composed AudioScript outlives the
|
|
664
|
+
* caption: it may anchor further captions and remains the text owner.
|
|
665
|
+
*/
|
|
666
|
+
private removeCaptionClipGraph;
|
|
667
|
+
private replaceAnchorHost;
|
|
668
|
+
/** Rebuild the legacy edit baseline from current visual order before a high-level cascade. */
|
|
669
|
+
private normalizeMainSequential;
|
|
670
|
+
private resolveOneVoiceoverOverlap;
|
|
671
|
+
private applyClipPlacement;
|
|
672
|
+
private reanchorAtAbsolute;
|
|
673
|
+
private removeAnchoredDescendants;
|
|
674
|
+
private removeClipGraph;
|
|
675
|
+
private transact;
|
|
676
|
+
private mintEntityId;
|
|
677
|
+
private createRelation;
|
|
678
|
+
private relinkRelation;
|
|
679
|
+
private mintRelationId;
|
|
680
|
+
}
|
|
681
|
+
//#endregion
|
|
682
|
+
//#region src/entity-editor/editor-resources.d.ts
|
|
683
|
+
declare const roleOrder: {
|
|
684
|
+
readonly caption: 0;
|
|
685
|
+
readonly video_clip: 1;
|
|
686
|
+
readonly speech: 2;
|
|
687
|
+
readonly bgm: 3;
|
|
688
|
+
};
|
|
689
|
+
type EditorTrackRole = keyof typeof roleOrder;
|
|
690
|
+
interface EditorFoundation {
|
|
691
|
+
readonly rows: EntityRelationRows;
|
|
692
|
+
readonly timelineEntityId: string;
|
|
693
|
+
readonly trackEntityIds: Readonly<Record<EditorTrackRole, string>>;
|
|
694
|
+
/** Initial or current AudioScript content ID selected by the foundation. */
|
|
695
|
+
readonly audioScriptEntityId: string | null;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* MEngine editor policy, not a cardinality restriction on the general-purpose DSL.
|
|
699
|
+
*
|
|
700
|
+
* Resources live on Asset entities and are reached through `from-asset`: no
|
|
701
|
+
* other entity carries a locator, one Asset claims each `(system, key)` pair,
|
|
702
|
+
* and media reaches at most one Asset. Media whose bytes are not named through
|
|
703
|
+
* that Relation is rejected rather than guessed at.
|
|
704
|
+
*/
|
|
705
|
+
declare function assertCanonicalEditorResources(rows: EntityRelationRows): void;
|
|
706
|
+
/**
|
|
707
|
+
* Commit-transition policy shared by the editor, the HTTP commit boundary, the
|
|
708
|
+
* host tool, and the entity stores. It compares the authoritative before and
|
|
709
|
+
* after rows of one CAS commit and enforces the resource rules on the complete
|
|
710
|
+
* after state, with no exemption for historical graphs:
|
|
711
|
+
*
|
|
712
|
+
* 1. every media Entity reaches exactly one Asset through `from-asset`;
|
|
713
|
+
* 2. no entity other than an Asset carries a locator;
|
|
714
|
+
* 3. an Asset's locator is immutable — pointing it at other bytes would
|
|
715
|
+
* silently rewrite every entity already made from it.
|
|
716
|
+
*
|
|
717
|
+
* Deleting media is explicit and allowed.
|
|
718
|
+
*/
|
|
719
|
+
declare function assertMediaAssetWritePolicy(before: EntityRelationRows, after: EntityRelationRows): void;
|
|
720
|
+
/** Add only missing editor structure; existing identities and owned settings are never replaced. */
|
|
721
|
+
declare function ensureEditorFoundation(initial: EntityRelationRows, idFactory?: EntityTimelineIdFactory, selectedAudioScriptEntityId?: string | null): EditorFoundation;
|
|
722
|
+
//#endregion
|
|
723
|
+
//#region src/entity-editor/media-asset-import.d.ts
|
|
724
|
+
interface ImportedMediaAsset {
|
|
725
|
+
readonly rows: EntityRelationRows;
|
|
726
|
+
/** The media entity for this asset id. */
|
|
727
|
+
readonly contentEntityId: string;
|
|
728
|
+
/** The Asset the media was made from; shared by every entity naming the same bytes. */
|
|
729
|
+
readonly assetEntityId: string;
|
|
730
|
+
/** The timbre identity of a synthesized voiceover; absent for recorded media. */
|
|
731
|
+
readonly voiceEntityId?: string;
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Import at the editor boundary, not at asset generation time. Existing
|
|
735
|
+
* provenance is retained.
|
|
736
|
+
*
|
|
737
|
+
* The bytes are named once, on an Asset entity, and the media entity reaches
|
|
738
|
+
* them through a `from-asset` Relation. Re-importing the same `(system, key)`
|
|
739
|
+
* reuses that Asset and the media already made from it, so one stored resource
|
|
740
|
+
* is never copied into several rows.
|
|
741
|
+
*/
|
|
742
|
+
declare function importMediaAsset(initial: EntityRelationRows, fact: MediaAssetFact, idFactory?: EntityTimelineIdFactory): ImportedMediaAsset;
|
|
743
|
+
//#endregion
|
|
744
|
+
//#region src/entity-editor/caption-content.d.ts
|
|
745
|
+
interface CaptionContentInput {
|
|
746
|
+
readonly contentEntityId: string;
|
|
747
|
+
readonly audioScriptEntityId: string;
|
|
748
|
+
readonly text: string;
|
|
749
|
+
readonly selection?: Caption['selection'];
|
|
750
|
+
readonly durationMs: number;
|
|
751
|
+
}
|
|
752
|
+
/** Author Caption content from semantic intent; callers never reconcile variant bases or assembled fields. */
|
|
753
|
+
declare function prepareCaptionContent(rows: EntityRelationRows, input: CaptionContentInput): EntityRow<'caption'>;
|
|
754
|
+
//#endregion
|
|
755
|
+
//#region src/entity-editor/document-audio-script.d.ts
|
|
756
|
+
interface DocumentAudioScript {
|
|
757
|
+
readonly entityId: string;
|
|
758
|
+
readonly segments: readonly ScriptSegment[];
|
|
759
|
+
}
|
|
760
|
+
/** State exposing the current AudioScript content version attached to the project. */
|
|
761
|
+
interface DocumentAudioScriptState {
|
|
762
|
+
readonly rows: EntityRelationRows;
|
|
763
|
+
/** Current attachment, or null until a script is transcribed or written. */
|
|
764
|
+
readonly audioScriptEntityId: string | null;
|
|
765
|
+
}
|
|
766
|
+
/** Read only the attached version and preserve every segment; never aggregate other scripts. */
|
|
767
|
+
declare function readDocumentAudioScript(state: DocumentAudioScriptState): DocumentAudioScript;
|
|
768
|
+
//#endregion
|
|
769
|
+
//#region src/entity-crdt/json-values.d.ts
|
|
770
|
+
/**
|
|
771
|
+
* What a Loro document stores and the wire carries. Entities never take this
|
|
772
|
+
* shape in code — their fields are typed by kind — only at the edge where a row
|
|
773
|
+
* becomes stored JSON, or JSON from outside becomes a row.
|
|
774
|
+
*/
|
|
775
|
+
type JsonPrimitive = string | number | boolean | null;
|
|
776
|
+
type JsonValue = JsonPrimitive | JsonObject | readonly JsonValue[];
|
|
777
|
+
type JsonObject = {
|
|
778
|
+
readonly [key: string]: JsonValue;
|
|
779
|
+
};
|
|
780
|
+
/**
|
|
781
|
+
* A plain object whose values are all JSON, however deep: finite numbers, no
|
|
782
|
+
* class instances, no cycles. Objects built in a script's VM realm pass, since
|
|
783
|
+
* their prototypes are that realm's `Object`, not this one's.
|
|
784
|
+
*/
|
|
785
|
+
declare function isJsonObject(value: unknown): value is JsonObject;
|
|
786
|
+
//#endregion
|
|
787
|
+
//#region src/entity-crdt/field-changes.d.ts
|
|
788
|
+
/** List members are addressed by identity, never a transient array offset. */
|
|
789
|
+
type FieldPath = readonly (string | {
|
|
790
|
+
elementId: string;
|
|
791
|
+
})[];
|
|
792
|
+
type FieldChange = {
|
|
793
|
+
op: 'set';
|
|
794
|
+
path: FieldPath;
|
|
795
|
+
value: JsonValue;
|
|
796
|
+
} | {
|
|
797
|
+
op: 'unset';
|
|
798
|
+
path: FieldPath;
|
|
799
|
+
} | {
|
|
800
|
+
op: 'text.splice';
|
|
801
|
+
path: FieldPath;
|
|
802
|
+
index: number;
|
|
803
|
+
deleteCount: number;
|
|
804
|
+
text: string;
|
|
805
|
+
} | {
|
|
806
|
+
op: 'list.insert';
|
|
807
|
+
path: FieldPath;
|
|
808
|
+
value: JsonValue;
|
|
809
|
+
beforeElementId: string | null;
|
|
810
|
+
} | {
|
|
811
|
+
op: 'list.move';
|
|
812
|
+
path: FieldPath;
|
|
813
|
+
elementId: string;
|
|
814
|
+
beforeElementId: string | null;
|
|
815
|
+
} | {
|
|
816
|
+
op: 'list.remove';
|
|
817
|
+
path: FieldPath;
|
|
818
|
+
elementId: string;
|
|
819
|
+
};
|
|
820
|
+
declare function assertFieldChanges(changes: readonly FieldChange[]): void;
|
|
821
|
+
/** Resolve against the sequential causal view; the numeric path never crosses the API boundary. */
|
|
822
|
+
declare function resolveFieldPath(payload: JsonObject, path: FieldPath): (string | number)[];
|
|
823
|
+
/** Detached plan evaluation. The Loro write replays the original operations, not this snapshot. */
|
|
824
|
+
declare function applyFieldChanges(payload: JsonObject, changes: readonly FieldChange[]): JsonObject;
|
|
825
|
+
//#endregion
|
|
826
|
+
//#region src/entity-crdt/entity-document.d.ts
|
|
827
|
+
declare const LORO_ENTITY_SCHEMA = "medeo.entities.loro.v1";
|
|
828
|
+
interface EntityDocumentState {
|
|
829
|
+
readonly rows: EntityRelationRows;
|
|
830
|
+
readonly project: Readonly<Record<string, string>>;
|
|
831
|
+
}
|
|
832
|
+
type Command = {
|
|
833
|
+
type: 'create';
|
|
834
|
+
row: EntityRow;
|
|
835
|
+
} | {
|
|
836
|
+
type: 'selection-baseline';
|
|
837
|
+
root: string;
|
|
838
|
+
fingerprint: string;
|
|
839
|
+
} | {
|
|
840
|
+
type: 'order';
|
|
841
|
+
group: string;
|
|
842
|
+
roots: string[];
|
|
843
|
+
token: string;
|
|
844
|
+
} | {
|
|
845
|
+
type: 'write';
|
|
846
|
+
root: string;
|
|
847
|
+
payload: JsonObject;
|
|
848
|
+
token: string;
|
|
849
|
+
} | {
|
|
850
|
+
type: 'text';
|
|
851
|
+
root: string;
|
|
852
|
+
path: readonly (string | number)[];
|
|
853
|
+
start: number;
|
|
854
|
+
deleteCount: number;
|
|
855
|
+
text: string;
|
|
856
|
+
token: string;
|
|
857
|
+
} | {
|
|
858
|
+
type: 'field';
|
|
859
|
+
root: string;
|
|
860
|
+
path: (string | number)[];
|
|
861
|
+
change: FieldChange;
|
|
862
|
+
token: string;
|
|
863
|
+
} | {
|
|
864
|
+
type: 'delete';
|
|
865
|
+
root: string;
|
|
866
|
+
} | {
|
|
867
|
+
type: 'relation';
|
|
868
|
+
row: RelationRow;
|
|
869
|
+
} | {
|
|
870
|
+
type: 'unlink';
|
|
871
|
+
root: string;
|
|
872
|
+
} | {
|
|
873
|
+
type: 'attach';
|
|
874
|
+
slot: string;
|
|
875
|
+
entityId: string;
|
|
876
|
+
};
|
|
877
|
+
/** Plain domain objects assembled from native Loro state, never a second writable authority. */
|
|
878
|
+
declare function readEntityDocument(doc: LoroDoc, allowSelectionConflicts?: boolean): EntityDocumentState;
|
|
879
|
+
/** Native editing containers survive domain version changes and merge independently. */
|
|
880
|
+
declare class LoroEntityDocument {
|
|
881
|
+
readonly doc: LoroDoc;
|
|
882
|
+
private readonly validate?;
|
|
883
|
+
private readonly undoManager;
|
|
884
|
+
constructor(doc: LoroDoc, validate?: ((state: EntityDocumentState) => void) | undefined);
|
|
885
|
+
/** Open the causal snapshot an edit is applied against. */
|
|
886
|
+
static fromSnapshot(snapshot: Uint8Array, validate?: (state: EntityDocumentState) => void): LoroEntityDocument;
|
|
887
|
+
static create(rows: EntityRelationRows, project?: Readonly<Record<string, string>>, peerId?: PeerID): LoroEntityDocument;
|
|
888
|
+
snapshot(): EntityDocumentState;
|
|
889
|
+
relationsOf(entityId: string): readonly RelationRow[];
|
|
890
|
+
/** Resolve a queued edit target through its native identity without changing history. */
|
|
891
|
+
resolveCurrentEntityId(id: string): string;
|
|
892
|
+
getVersion(id: string): EntityRow | undefined;
|
|
893
|
+
/** The callback and every domain validation execute on a causally complete fork first. */
|
|
894
|
+
transact(edit: (draft: LoroEntityDraft) => void): Uint8Array;
|
|
895
|
+
/** Import preserves native operation identities; projection errors never discard remote operations. */
|
|
896
|
+
import(update: Uint8Array): void;
|
|
897
|
+
/**
|
|
898
|
+
* Bind a saved snapshot without rewriting text operations or resolving
|
|
899
|
+
* selection conflicts. The script names the bytes the same way everything
|
|
900
|
+
* else does — an Asset entity plus a Relation — and the Asset's digest says
|
|
901
|
+
* which content they hold, which is what tells a stale snapshot from a
|
|
902
|
+
* current one. The Relation is `to-asset`: these bytes are the script's own
|
|
903
|
+
* content written out, not a source it was made from, so the Asset is
|
|
904
|
+
* `writable`.
|
|
905
|
+
*/
|
|
906
|
+
bindScriptAsset(entityId: string, snapshot: {
|
|
907
|
+
readonly key: string;
|
|
908
|
+
readonly digest: string;
|
|
909
|
+
}): Uint8Array;
|
|
910
|
+
canUndo(): boolean;
|
|
911
|
+
canRedo(): boolean;
|
|
912
|
+
undo(): boolean;
|
|
913
|
+
redo(): boolean;
|
|
914
|
+
private historyEdit;
|
|
915
|
+
}
|
|
916
|
+
declare class LoroEntityDraft {
|
|
917
|
+
private readonly doc;
|
|
918
|
+
readonly commands: Command[];
|
|
919
|
+
private readonly selectedRoots;
|
|
920
|
+
private readonly relationAliases;
|
|
921
|
+
constructor(doc: LoroDoc);
|
|
922
|
+
snapshot(): EntityDocumentState;
|
|
923
|
+
order(groupId: string, entityIds: readonly string[]): void;
|
|
924
|
+
/** Project the final scalar placement intents onto the existing native ordering containers. */
|
|
925
|
+
reconcileOrder(rows: EntityRelationRows): void;
|
|
926
|
+
create(row: EntityRow): void;
|
|
927
|
+
delete(entityId: string): void;
|
|
928
|
+
attach(slot: string, entityId: string): void;
|
|
929
|
+
link(row: RelationRow): void;
|
|
930
|
+
unlink(relationId: string): void;
|
|
931
|
+
private relationRoot;
|
|
932
|
+
update(entityId: string, fields: Partial<EntityRow['payload']>): void;
|
|
933
|
+
declare(entityId: string, fields: Partial<EntityRow['payload']>): void;
|
|
934
|
+
replaceOwned(entityId: string, payload: EntityRow['payload']): void;
|
|
935
|
+
private write;
|
|
936
|
+
editText(entityId: string, path: readonly (string | number)[], start: number, deleteCount: number, text: string): void;
|
|
937
|
+
/** Generic assembled-field edit applied at the author's causal position. */
|
|
938
|
+
change(entityId: string, changes: readonly FieldChange[]): void;
|
|
939
|
+
captureSelectionBaselines(): void;
|
|
940
|
+
private record;
|
|
941
|
+
}
|
|
942
|
+
//#endregion
|
|
943
|
+
//#region src/entity-crdt/apply.d.ts
|
|
944
|
+
/**
|
|
945
|
+
* Apply rows to a document as native Loro operations, returning the update.
|
|
946
|
+
* On a live peer the edit joins its local undo history; an edit made on an
|
|
947
|
+
* earlier baseline is applied to `LoroEntityDocument.fromSnapshot` of it.
|
|
948
|
+
*/
|
|
949
|
+
declare function apply(editor: LoroEntityDocument, rows: EntityRelationRows): {
|
|
950
|
+
update: Uint8Array;
|
|
951
|
+
state: EntityDocumentState;
|
|
952
|
+
};
|
|
953
|
+
//#endregion
|
|
954
|
+
//#region src/editor/id-gen.d.ts
|
|
955
|
+
/**
|
|
956
|
+
* Part-id generation, aligned with the online ecosystem.
|
|
957
|
+
*
|
|
958
|
+
* The authoritative online producers — agent-harness (`@harness/shared`
|
|
959
|
+
* `genObjId`) and director.v2 (`common/obj_id.py` `gen_obj_id`) — both mint part
|
|
960
|
+
* ids as `` `${prefix}_${ulid()}` ``, and real captured drafts use exactly that
|
|
961
|
+
* shape (`clip_…` / `spe_…` / `cap_…` / `bgm_…`, each a 26-char ULID). The engine
|
|
962
|
+
* previously emitted `vc_<base36 timestamp><6 random>`, a different prefix AND a
|
|
963
|
+
* different encoding — the sole cross-repo id divergence. This module removes it
|
|
964
|
+
* by emitting the same `<prefix>_<ULID>` bytes.
|
|
965
|
+
*
|
|
966
|
+
* The ULID is generated inline (Crockford Base32, 48-bit time + 80-bit random)
|
|
967
|
+
* rather than pulling the `ulid` npm package: the randomness class matches the
|
|
968
|
+
* old generator (both `Math.random`-based) and it keeps `@mengine/medeo-client`
|
|
969
|
+
* dependency-free for a purely mechanical id string. Part ids only need to be
|
|
970
|
+
* unique and lexicographically time-sortable, which this satisfies.
|
|
971
|
+
*/
|
|
972
|
+
/**
|
|
973
|
+
* Online part-id semantic prefixes. `clip` (video clip) is the only value the
|
|
974
|
+
* engine currently mints (see `addVideoClips`); the rest are declared so the
|
|
975
|
+
* type documents the shared vocabulary and guards against reintroducing the old
|
|
976
|
+
* `vc`/`sp`/`cp`/`bg` names. Speech/caption/bgm ids arrive pre-minted in op
|
|
977
|
+
* payloads, so the engine never generates them itself.
|
|
978
|
+
*/
|
|
979
|
+
type PartIdPrefix = 'clip' | 'spe' | 'cap' | 'bgm' | 'ti';
|
|
980
|
+
declare function generatePartId(prefix: PartIdPrefix): string;
|
|
981
|
+
/** Injectable part-id mint; retained for the legacy entity sandbox host. */
|
|
982
|
+
type PartIdFactory = (prefix: PartIdPrefix) => string;
|
|
983
|
+
//#endregion
|
|
984
|
+
//#region src/legacy/retired-journal.d.ts
|
|
985
|
+
/** Retained wire shape for rejecting obsolete timeline plans; entity plans use their own journal. */
|
|
986
|
+
interface JournalEntry extends CommitOptions {
|
|
987
|
+
kind: string;
|
|
988
|
+
payload: unknown;
|
|
989
|
+
generated_ids: string[];
|
|
990
|
+
}
|
|
991
|
+
//#endregion
|
|
992
|
+
//#region src/legacy/manual-sync-doc.d.ts
|
|
993
|
+
/** Legacy entity tools only. The retired timeline document has no editing or reading adapter. */
|
|
994
|
+
declare class ManualSyncDoc extends ManualSyncTransport {
|
|
995
|
+
private constructor();
|
|
996
|
+
static open(options: ManualSyncDocOptions): Promise<ManualSyncDoc>;
|
|
997
|
+
isEntityDocument(): boolean;
|
|
998
|
+
content(): VideoDraftContent;
|
|
999
|
+
}
|
|
1000
|
+
//#endregion
|
|
1001
|
+
//#region src/entity-crdt/audio-script-assets.d.ts
|
|
1002
|
+
/** The bytes a resource is stored as: its JSON text, exactly as uploaded. */
|
|
1003
|
+
declare function assetBytes(content: JsonObject): Uint8Array;
|
|
1004
|
+
/** The fingerprint of those bytes: `sha256:` and the hex of their SHA-256. */
|
|
1005
|
+
declare function assetDigest(content: JsonObject): string;
|
|
1006
|
+
/** A resource is a snapshot of text; the native Loro text remains the editing authority. */
|
|
1007
|
+
declare function audioScriptAssetContent(rows: EntityRelationRows, entityId: string): JsonObject;
|
|
1008
|
+
/** What a script's snapshot holds, which is a different document for each kind of script. */
|
|
1009
|
+
declare function scriptAssetContent(rows: EntityRelationRows, entityId: string): JsonObject;
|
|
1010
|
+
/**
|
|
1011
|
+
* Whether a script's snapshot still holds its content: the Asset's digest is
|
|
1012
|
+
* that of what the script would be saved as now.
|
|
1013
|
+
*
|
|
1014
|
+
* Only a `writable` Asset can be judged this way, because only for bytes this
|
|
1015
|
+
* document wrote is the digest one it can work out again. Anything else holds a
|
|
1016
|
+
* store's bytes and is left alone; a writable one with no digest cannot say
|
|
1017
|
+
* what it holds, so the content is written out again.
|
|
1018
|
+
*/
|
|
1019
|
+
declare function scriptSnapshotIsCurrent(rows: EntityRelationRows, entityId: string): boolean;
|
|
1020
|
+
/**
|
|
1021
|
+
* The Asset a script was written out to. It is a snapshot the script owns, so
|
|
1022
|
+
* it is reached by `to-asset` — not `from-asset`, which would say the script
|
|
1023
|
+
* was produced from bytes it cannot change.
|
|
1024
|
+
*/
|
|
1025
|
+
declare function scriptSnapshotAssetOf(rows: EntityRelationRows, entityId: string): EntityRow<'asset'> | undefined;
|
|
1026
|
+
/**
|
|
1027
|
+
* The Asset a script was made from — a transcript it does not own. A script
|
|
1028
|
+
* that has one never writes a snapshot of its own: the bytes it would describe
|
|
1029
|
+
* are already named, and rewriting them would contradict their source.
|
|
1030
|
+
*/
|
|
1031
|
+
declare function scriptSourceAssetOf(rows: EntityRelationRows, entityId: string): EntityRow<'asset'> | undefined;
|
|
1032
|
+
/**
|
|
1033
|
+
* What a PhoneticScript hands to synthesis: the base AudioScript's text as the
|
|
1034
|
+
* variant pronounces it, plus the variant's own phoneme control.
|
|
1035
|
+
*
|
|
1036
|
+
* The variant's content is written by a model — deciding how words are said is
|
|
1037
|
+
* text work, not a mechanical copy — but the bytes a synthesizer reads have to
|
|
1038
|
+
* leave the entity graph to reach it, because synthesis does not handle
|
|
1039
|
+
* entities. Writing this resource down is that crossing, and it is why speech
|
|
1040
|
+
* can only come from a PhoneticScript.
|
|
1041
|
+
*/
|
|
1042
|
+
declare function phoneticScriptAssetContent(rows: EntityRelationRows, entityId: string): JsonObject;
|
|
1043
|
+
//#endregion
|
|
1044
|
+
export { type AudioMediaAssetFact, type CaptionContentInput, type CaptionDisplayCue, type ClipEntityId, type ClipPlacement, type DeleteBgmInput, type DeleteClipInput, type DeleteClipTreeInput, type DeleteVoiceoverInput, type DocStorageLike, DocVersionMark, type DocumentAudioScript, type DocumentAudioScriptState, type EditorFoundation, EntityDocumentState, type EntityGraphCommitOptions, EntityGraphHttpClient, type EntityGraphState, EntityProjectionGraph, EntityTimelineEditor, type EntityTimelineIdFactory, EntityTimelineProjectionError, EntityTimelineTrackRole, type FieldChange, type FieldPath, type ImageMediaAssetFact, type ImportedMediaAsset, type InsertCaptionClipInput, type InsertClipInput, type InsertMediaClipInput, type InsertMediaClipsInput, type InsertPlacedClipInput, type JournalEntry, JsonObject, JsonPrimitive, JsonValue, LORO_ENTITY_SCHEMA, type LinearClipSpeed, LoroEntityDocument, LoroEntityDraft, ManualSyncDoc, type ManualSyncDocOptions, MedeoHttpDocStorage, type MedeoHttpDocStorageOptions, type MediaAssetFact, type MediaClipInsertion, MemoryDocStorage, type MengineAuditEntry, type MengineAuditResponse, type MengineDocSessionOptions, type MengineDocSyncState, type MengineDocumentVersion, type MengineDraftResponse, type MengineEventStreamOptions, MengineHttpClient, type MengineHttpClientOptions, MengineHttpRequestError, MenginePushRejectedError, type MenginePushResponse, type MenginePushUpdateResponse, type MengineRejectedResponse, type MengineSnapshotResponse, type MengineSseUpdateEvent, type MengineSyncResponse, type MengineUndoState, type MengineUpdateMeta, type MoveClipInput, type MoveClipsToStartsInput, type MoveSequentialClipsInput, type MoveVoiceoverInput, type PartIdFactory, type PatchCaptionStyleInput, PullFailureReason, PullResult, type PushOutcome, type PushOutcomeKind, PushResult, PushResultKind, type ReplaceClipContentInput, type ReplaceMediaClipInput, type ReplaceSequentialClipsInput, type ReplacementMediaClipInput, ResolvedEntityClipPlacement, ResolvedEntityTimelineLayout, ResolvedEntityTrack, ScriptCompositionError, type SequentialClipAnchor, type SetBgmInput, type SetCaptionVisibilityInput, type SetClipPlacementInput, type SetClipSpeedInput, type SetClipVolumeInput, type TrimClipInput, type UpdateClipInput, type UpdateClipMarkerInput, type VideoDraft, type VideoDraftContent, type VideoDraftPartUnion, type VideoMediaAssetFact, type VisualMediaAssetFact, type VoiceoverCaptionFact, type VoiceoverMediaAssetFact, type VoiceoverTakeInput, type VoiceoverTakeResult, type WaitForServerAckOptions, apply, applyFieldChanges, assembleEntityContent, assembleScriptText, assertCanonicalEditorResources, assertFieldChanges, assertMediaAssetWritePolicy, assetBytes, assetDigest, audioScriptAssetContent, base64ToBytes, bytesToBase64, decodeDocVersionMark, encodeDocVersionMark, ensureEditorFoundation, generatePartId, importMediaAsset, isJsonObject, phoneticScriptAssetContent, prepareCaptionContent, projectEntityTimeline, readDocumentAudioScript, readEntityDocument, readMengineEventStream, resolveEntityFieldOwner, resolveEntityTimelineLayout, resolveFieldPath, resolveGraphLayout, scriptAssetContent, scriptSnapshotAssetOf, scriptSnapshotIsCurrent, scriptSourceAssetOf, segmentsOf, selectedSegment };
|