@mengine/medeo-client 2.1.1-dsl.0 → 2.1.1-dsl.10
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 +27 -12
- package/dist/dsl-COyzz7Fp.js +6395 -0
- package/dist/dsl.d.ts +3 -3
- package/dist/dsl.js +3 -3
- package/dist/index-C5wDKYqC.d.ts +953 -0
- package/dist/{index-DQZUkrpg.d.ts → index-CHiPztZr.d.ts} +53 -56
- package/dist/{index-B7fC7q7P.d.ts → index-DAfOkcnZ.d.ts} +23 -4
- package/dist/index.d.ts +5 -5
- package/dist/index.js +65 -9
- package/dist/legacy.d.ts +2 -2
- package/dist/legacy.js +1 -1
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +4 -7
- package/dist/video-draft-types-BnbfWrBx.js +1486 -0
- package/dist/{video-draft-types-c_shaRyq.d.ts → video-draft-types-GqXnsOzA.d.ts} +114 -54
- package/package.json +8 -5
- package/dist/dsl-Dkecq_2c.js +0 -2814
- package/dist/index-DKDMTXUe.d.ts +0 -605
- package/dist/video-draft-types-DTXxvPt-.js +0 -449
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
|
-
import { Cursor } from "loro-crdt";
|
|
3
|
-
import { schema } from "loro-mirror";
|
|
4
|
-
//#region ../medeo-dsl/src/ids.ts
|
|
5
|
-
function bytesToBase64url(bytes) {
|
|
6
|
-
let binary = "";
|
|
7
|
-
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
8
|
-
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
9
|
-
}
|
|
10
|
-
function base64urlToBytes(value) {
|
|
11
|
-
if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1) throw new Error("Invalid base64url");
|
|
12
|
-
const bytes = Uint8Array.from(atob(value.replaceAll("-", "+").replaceAll("_", "/")), (c) => c.charCodeAt(0));
|
|
13
|
-
if (bytesToBase64url(bytes) !== value) throw new Error("Non-canonical base64url");
|
|
14
|
-
return bytes;
|
|
15
|
-
}
|
|
16
|
-
function tupleHash(tuple) {
|
|
17
|
-
return bytesToBase64url(sha256(new TextEncoder().encode(JSON.stringify(tuple))));
|
|
18
|
-
}
|
|
19
|
-
function resourceId(kind, system, key) {
|
|
20
|
-
return `${kind}:${tupleHash([system, key])}`;
|
|
21
|
-
}
|
|
22
|
-
function relationId(table, value) {
|
|
23
|
-
const v = value;
|
|
24
|
-
switch (table) {
|
|
25
|
-
case "clip-source-relations": return `cs:${v.clipId}`;
|
|
26
|
-
case "time-anchor-relations": return `ta:${v.from}`;
|
|
27
|
-
case "caption-content-relations": return `cc:${v.captionId}`;
|
|
28
|
-
case "caption-alignment-relations": return `ca:${v.captionId}`;
|
|
29
|
-
case "voice-timbre-relations": return `voice-timbre:${tupleHash([v.recordingId, v.voiceId])}`;
|
|
30
|
-
case "derived-from-relations": return `derived-from:${tupleHash([v.entityId, v.sourceId])}`;
|
|
31
|
-
case "from-asset-relations": return `from-asset:${v.audioScriptId}`;
|
|
32
|
-
case "to-asset-relations": return `to-asset:${v.audioScriptId}`;
|
|
33
|
-
}
|
|
34
|
-
throw new Error(`Unknown relation table: ${table}`);
|
|
35
|
-
}
|
|
36
|
-
const defaultIdFactory = (kind) => `${kind}_${globalThis.crypto.randomUUID()}`;
|
|
37
|
-
const resourceKinds = {
|
|
38
|
-
"media-entities": "media",
|
|
39
|
-
"voice-entities": "voice",
|
|
40
|
-
"asset-entities": "asset"
|
|
41
|
-
};
|
|
42
|
-
/** A resource row's ID is derived from its locator, so one external resource is one entity. */
|
|
43
|
-
function assertResourceIdentity(table, id, value) {
|
|
44
|
-
const kind = resourceKinds[table];
|
|
45
|
-
if (kind && id !== resourceId(kind, value.system, value.key)) throw new Error("Resource identity does not match locator");
|
|
46
|
-
}
|
|
47
|
-
/** A relation row's ID is derived from its uniqueness key. */
|
|
48
|
-
function assertRelationIdentity(table, id, value) {
|
|
49
|
-
if (id !== relationId(table, value)) throw new Error("Relation ID does not match endpoints");
|
|
50
|
-
}
|
|
51
|
-
//#endregion
|
|
52
|
-
//#region ../medeo-dsl/src/fields.ts
|
|
53
|
-
const string = (v) => typeof v === "string";
|
|
54
|
-
const nonempty = (v) => string(v) && v.length > 0;
|
|
55
|
-
const finite = (v) => typeof v === "number" && Number.isFinite(v);
|
|
56
|
-
const integer = (v) => typeof v === "number" && Number.isSafeInteger(v);
|
|
57
|
-
const nonnegative = (v) => integer(v) && v >= 0;
|
|
58
|
-
const positive = (v) => integer(v) && v > 0;
|
|
59
|
-
const oneOf = (...values) => (v) => values.includes(v);
|
|
60
|
-
const required = (check) => ({ check });
|
|
61
|
-
const optional$1 = (check) => ({
|
|
62
|
-
check,
|
|
63
|
-
optional: true
|
|
64
|
-
});
|
|
65
|
-
function isRecord(value) {
|
|
66
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Cursor);
|
|
67
|
-
}
|
|
68
|
-
function assertId(value) {
|
|
69
|
-
if (!nonempty(value) || [
|
|
70
|
-
"$cid",
|
|
71
|
-
"__proto__",
|
|
72
|
-
"constructor",
|
|
73
|
-
"prototype"
|
|
74
|
-
].includes(value)) throw new Error("Expected a nonempty, non-reserved ID");
|
|
75
|
-
}
|
|
76
|
-
function validLanguage(value) {
|
|
77
|
-
if (typeof value !== "string") return false;
|
|
78
|
-
if (/^x(?:-[a-z0-9]{1,8})+$/i.test(value)) return true;
|
|
79
|
-
try {
|
|
80
|
-
return value.length > 0 && Intl.getCanonicalLocales(value).length === 1;
|
|
81
|
-
} catch {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
function object(fields) {
|
|
86
|
-
return (v) => {
|
|
87
|
-
try {
|
|
88
|
-
checkFields(v, fields);
|
|
89
|
-
return true;
|
|
90
|
-
} catch {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
function checkFields(value, fields, partial = false) {
|
|
96
|
-
if (!isRecord(value)) throw new Error("Expected an object");
|
|
97
|
-
for (const key of Object.keys(value)) if (!Object.hasOwn(fields, key)) throw new Error(`Unknown field: ${key}`);
|
|
98
|
-
for (const [key, field] of Object.entries(fields)) {
|
|
99
|
-
if (partial && !Object.hasOwn(value, key)) continue;
|
|
100
|
-
const v = value[key];
|
|
101
|
-
if (v === void 0 && field.optional) continue;
|
|
102
|
-
if (!field.check(v)) throw new Error(`Invalid or missing field: ${key}`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
const styleFields = {
|
|
106
|
-
font: optional$1(object({
|
|
107
|
-
system: required(oneOf("font-library")),
|
|
108
|
-
key: required(nonempty)
|
|
109
|
-
})),
|
|
110
|
-
fontSize: optional$1(finite),
|
|
111
|
-
fontColor: optional$1(string),
|
|
112
|
-
fontWeight: optional$1(finite),
|
|
113
|
-
entranceAnimation: optional$1(string),
|
|
114
|
-
entranceAnimationDurationMs: optional$1(nonnegative),
|
|
115
|
-
strokeColor: optional$1(string),
|
|
116
|
-
strokeWidth: optional$1(finite),
|
|
117
|
-
positionX: optional$1(finite),
|
|
118
|
-
positionY: optional$1(finite)
|
|
119
|
-
};
|
|
120
|
-
const seqMarkerFields = {
|
|
121
|
-
inMs: required(nonnegative),
|
|
122
|
-
outMs: required(nonnegative),
|
|
123
|
-
rate: optional$1((v) => finite(v) && v > 0),
|
|
124
|
-
fillTimeline: optional$1(oneOf(true))
|
|
125
|
-
};
|
|
126
|
-
/** A sequence marker's own fields; the window being nonempty is checked where it is written. */
|
|
127
|
-
function assertSeqMarker(value) {
|
|
128
|
-
checkFields(value, seqMarkerFields);
|
|
129
|
-
}
|
|
130
|
-
const locator = {
|
|
131
|
-
system: required(oneOf("memota", "memota-speech")),
|
|
132
|
-
key: required(nonempty)
|
|
133
|
-
};
|
|
134
|
-
const entityFields = {
|
|
135
|
-
"timeline-entities": {},
|
|
136
|
-
"track-entities": {
|
|
137
|
-
role: required(oneOf("video_clip", "speech", "caption", "bgm")),
|
|
138
|
-
hidden: optional$1((v) => typeof v === "boolean")
|
|
139
|
-
},
|
|
140
|
-
"clip-entities": {
|
|
141
|
-
seqMarker: required(object(seqMarkerFields)),
|
|
142
|
-
volume: optional$1(finite)
|
|
143
|
-
},
|
|
144
|
-
"media-entities": {
|
|
145
|
-
...locator,
|
|
146
|
-
kind: required(oneOf("video", "audio", "voiceover-recording", "image")),
|
|
147
|
-
storageKey: optional$1(nonempty),
|
|
148
|
-
durationMs: optional$1(positive),
|
|
149
|
-
digest: optional$1(nonempty)
|
|
150
|
-
},
|
|
151
|
-
"audio-script-entities": {
|
|
152
|
-
body: required(string),
|
|
153
|
-
defaultLanguage: optional$1(validLanguage)
|
|
154
|
-
},
|
|
155
|
-
"caption-entities": {
|
|
156
|
-
text: optional$1(string),
|
|
157
|
-
style: optional$1(object(styleFields))
|
|
158
|
-
},
|
|
159
|
-
"voice-entities": {
|
|
160
|
-
system: required(oneOf("voice-library")),
|
|
161
|
-
key: required(nonempty),
|
|
162
|
-
name: optional$1(string)
|
|
163
|
-
},
|
|
164
|
-
"asset-entities": {
|
|
165
|
-
...locator,
|
|
166
|
-
storageKey: optional$1(nonempty),
|
|
167
|
-
digest: optional$1(nonempty)
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
const entityTables = Object.keys(entityFields);
|
|
171
|
-
const relationFields = {
|
|
172
|
-
"clip-source-relations": {
|
|
173
|
-
clipId: required(nonempty),
|
|
174
|
-
sourceId: required(nonempty)
|
|
175
|
-
},
|
|
176
|
-
"time-anchor-relations": {
|
|
177
|
-
from: required(nonempty),
|
|
178
|
-
to: required(nonempty),
|
|
179
|
-
offsetMs: required(integer),
|
|
180
|
-
fallback_abs_ms: required(nonnegative)
|
|
181
|
-
},
|
|
182
|
-
"caption-content-relations": {
|
|
183
|
-
captionId: required(nonempty),
|
|
184
|
-
audioScriptId: required(nonempty),
|
|
185
|
-
start: required((v) => v instanceof Cursor),
|
|
186
|
-
end: required((v) => v instanceof Cursor)
|
|
187
|
-
},
|
|
188
|
-
"caption-alignment-relations": {
|
|
189
|
-
captionId: required(nonempty),
|
|
190
|
-
mediaId: required(nonempty),
|
|
191
|
-
startMs: required(nonnegative),
|
|
192
|
-
endMs: required(nonnegative)
|
|
193
|
-
},
|
|
194
|
-
"voice-timbre-relations": {
|
|
195
|
-
recordingId: required(nonempty),
|
|
196
|
-
voiceId: required(nonempty)
|
|
197
|
-
},
|
|
198
|
-
"derived-from-relations": {
|
|
199
|
-
entityId: required(nonempty),
|
|
200
|
-
sourceId: required(nonempty)
|
|
201
|
-
},
|
|
202
|
-
"from-asset-relations": {
|
|
203
|
-
audioScriptId: required(nonempty),
|
|
204
|
-
assetId: required(nonempty)
|
|
205
|
-
},
|
|
206
|
-
"to-asset-relations": {
|
|
207
|
-
audioScriptId: required(nonempty),
|
|
208
|
-
assetId: required(nonempty)
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
const relationTables = Object.keys(relationFields);
|
|
212
|
-
function assertEntity(table, value) {
|
|
213
|
-
checkFields(value, entityFields[table]);
|
|
214
|
-
if (table === "media-entities") {
|
|
215
|
-
if (value.kind === "image" && value.durationMs !== void 0) throw new Error("Image has no intrinsic duration");
|
|
216
|
-
if (value.kind !== "image" && !positive(value.durationMs)) throw new Error("Finite media requires durationMs");
|
|
217
|
-
if (["audio", "voiceover-recording"].includes(value.kind) && !nonempty(value.storageKey)) throw new Error("Audio requires storageKey");
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
/** Validate only touched fields, so an unrelated edit can proceed in a merged, invalid document. */
|
|
221
|
-
function assertEntityPatch(table, patch, current) {
|
|
222
|
-
if (!isRecord(patch)) throw new Error("Expected an entity patch");
|
|
223
|
-
if (table === "audio-script-entities" && Object.hasOwn(patch, "body")) throw new Error("Edit body through the Text adapter");
|
|
224
|
-
if (table === "caption-entities" && current.style !== void 0 && Object.hasOwn(patch, "style") && patch.style === void 0) throw new Error("Reset individual style fields; retain the style Map");
|
|
225
|
-
if (table === "caption-entities" && current.text !== void 0 && patch.text !== void 0) throw new Error("Edit Caption text through the Text adapter");
|
|
226
|
-
const next = mergeFields(current, patch);
|
|
227
|
-
for (const key of Object.keys(patch)) {
|
|
228
|
-
const field = entityFields[table][key];
|
|
229
|
-
if (!field || !field.optional && next[key] === void 0 || next[key] !== void 0 && !field.check(next[key])) throw new Error(`Invalid patch field: ${key}`);
|
|
230
|
-
}
|
|
231
|
-
if (table === "media-entities" || table === "voice-entities" || table === "asset-entities") {
|
|
232
|
-
for (const key of [
|
|
233
|
-
"system",
|
|
234
|
-
"key",
|
|
235
|
-
"kind"
|
|
236
|
-
]) if (Object.hasOwn(patch, key) && patch[key] !== current[key]) throw new Error(`Resource identity field is immutable: ${key}`);
|
|
237
|
-
}
|
|
238
|
-
if (table === "media-entities") {
|
|
239
|
-
if (Object.hasOwn(patch, "durationMs")) {
|
|
240
|
-
if (next.kind === "image" ? next.durationMs !== void 0 : !positive(next.durationMs)) throw new Error("durationMs must match the media kind");
|
|
241
|
-
}
|
|
242
|
-
if (Object.hasOwn(patch, "storageKey") && ["audio", "voiceover-recording"].includes(next.kind) && !nonempty(next.storageKey)) throw new Error("Audio requires storageKey");
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
function assertRelation(table, value) {
|
|
246
|
-
checkFields(value, relationFields[table]);
|
|
247
|
-
for (const [key, endpoint] of Object.entries(value)) if (key.endsWith("Id") || key === "from" || key === "to") assertId(endpoint);
|
|
248
|
-
}
|
|
249
|
-
/** Undefined deletes; nested patches retain sibling fields and an existing empty style Map. */
|
|
250
|
-
function mergeFields(target, patch) {
|
|
251
|
-
const result = { ...target };
|
|
252
|
-
for (const [key, value] of Object.entries(patch)) {
|
|
253
|
-
if ([
|
|
254
|
-
"$cid",
|
|
255
|
-
"__proto__",
|
|
256
|
-
"constructor",
|
|
257
|
-
"prototype"
|
|
258
|
-
].includes(key)) throw new Error(`Reserved field: ${key}`);
|
|
259
|
-
if (value === void 0) delete result[key];
|
|
260
|
-
else result[key] = isRecord(value) ? mergeFields(isRecord(result[key]) ? result[key] : {}, value) : value;
|
|
261
|
-
}
|
|
262
|
-
return result;
|
|
263
|
-
}
|
|
264
|
-
//#endregion
|
|
265
|
-
//#region ../medeo-dsl/src/schema/codec.ts
|
|
266
|
-
function isInvalidAtomic(value) {
|
|
267
|
-
return typeof value === "object" && value !== null && "invalid" in value && value.invalid === true;
|
|
268
|
-
}
|
|
269
|
-
function codec(encode, decode) {
|
|
270
|
-
return {
|
|
271
|
-
encode: (v) => isInvalidAtomic(v) ? v.raw : encode(v),
|
|
272
|
-
decode: (raw) => {
|
|
273
|
-
try {
|
|
274
|
-
return decode(raw);
|
|
275
|
-
} catch (error) {
|
|
276
|
-
return {
|
|
277
|
-
invalid: true,
|
|
278
|
-
raw,
|
|
279
|
-
reason: String(error)
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
const timeAnchorCodec = codec((v) => {
|
|
286
|
-
assertRelation("time-anchor-relations", v);
|
|
287
|
-
return JSON.stringify({
|
|
288
|
-
from: v.from,
|
|
289
|
-
to: v.to,
|
|
290
|
-
offsetMs: v.offsetMs,
|
|
291
|
-
fallback_abs_ms: v.fallback_abs_ms
|
|
292
|
-
});
|
|
293
|
-
}, (raw) => {
|
|
294
|
-
const v = JSON.parse(raw);
|
|
295
|
-
assertRelation("time-anchor-relations", v);
|
|
296
|
-
return v;
|
|
297
|
-
});
|
|
298
|
-
const captionContentCodec = codec((v) => {
|
|
299
|
-
assertRelation("caption-content-relations", v);
|
|
300
|
-
return JSON.stringify({
|
|
301
|
-
captionId: v.captionId,
|
|
302
|
-
audioScriptId: v.audioScriptId,
|
|
303
|
-
start: bytesToBase64url(v.start.encode()),
|
|
304
|
-
end: bytesToBase64url(v.end.encode())
|
|
305
|
-
});
|
|
306
|
-
}, (raw) => {
|
|
307
|
-
const v = JSON.parse(raw);
|
|
308
|
-
if (typeof v?.start !== "string" || typeof v?.end !== "string") throw new Error("Expected encoded Cursor pair");
|
|
309
|
-
const value = {
|
|
310
|
-
...v,
|
|
311
|
-
start: Cursor.decode(base64urlToBytes(v.start)),
|
|
312
|
-
end: Cursor.decode(base64urlToBytes(v.end))
|
|
313
|
-
};
|
|
314
|
-
assertRelation("caption-content-relations", value);
|
|
315
|
-
return value;
|
|
316
|
-
});
|
|
317
|
-
/** A Clip's sequence marker is stored as one string, so it is taken or replaced whole. */
|
|
318
|
-
const seqMarkerCodec = codec((v) => {
|
|
319
|
-
assertSeqMarker(v);
|
|
320
|
-
return JSON.stringify({
|
|
321
|
-
inMs: v.inMs,
|
|
322
|
-
outMs: v.outMs,
|
|
323
|
-
...v.rate === void 0 ? {} : { rate: v.rate },
|
|
324
|
-
...v.fillTimeline === void 0 ? {} : { fillTimeline: v.fillTimeline }
|
|
325
|
-
});
|
|
326
|
-
}, (raw) => {
|
|
327
|
-
const v = JSON.parse(raw);
|
|
328
|
-
assertSeqMarker(v);
|
|
329
|
-
return v;
|
|
330
|
-
});
|
|
331
|
-
//#endregion
|
|
332
|
-
//#region ../medeo-dsl/src/schema/loro-shape.ts
|
|
333
|
-
const optional = { required: false };
|
|
334
|
-
const mergeable = { mergeableMapChildContainers: true };
|
|
335
|
-
const strings = (keys) => Object.fromEntries(keys.map((key) => [key, schema.String()]));
|
|
336
|
-
const relation = (keys) => schema.LoroMapRecord(schema.LoroMap(strings(keys)), mergeable);
|
|
337
|
-
const atomicValue = (codec) => schema.String().transform({
|
|
338
|
-
...codec,
|
|
339
|
-
isEqual: "encoded-value-equality",
|
|
340
|
-
validateEncodedType: true
|
|
341
|
-
});
|
|
342
|
-
const atomic = (codec) => schema.LoroMapRecord(atomicValue(codec));
|
|
343
|
-
/** Only direct children inherit mergeable identity. Body and ordinary entity rows keep normal identities. */
|
|
344
|
-
const medeoDslLoroShape = schema({
|
|
345
|
-
"timeline-entities": schema.LoroMapRecord(schema.LoroMap({})),
|
|
346
|
-
"track-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
347
|
-
role: schema.String(),
|
|
348
|
-
hidden: schema.Boolean(optional)
|
|
349
|
-
})),
|
|
350
|
-
"clip-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
351
|
-
seqMarker: atomicValue(seqMarkerCodec),
|
|
352
|
-
volume: schema.Number(optional)
|
|
353
|
-
})),
|
|
354
|
-
"media-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
355
|
-
kind: schema.String(),
|
|
356
|
-
system: schema.String(),
|
|
357
|
-
key: schema.String(),
|
|
358
|
-
storageKey: schema.String(optional),
|
|
359
|
-
durationMs: schema.Number(optional),
|
|
360
|
-
digest: schema.String(optional)
|
|
361
|
-
}), mergeable),
|
|
362
|
-
"audio-script-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
363
|
-
body: schema.LoroText(),
|
|
364
|
-
defaultLanguage: schema.String(optional)
|
|
365
|
-
})),
|
|
366
|
-
"caption-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
367
|
-
text: schema.LoroText(optional),
|
|
368
|
-
style: schema.LoroMap({
|
|
369
|
-
font: schema.LoroMap({
|
|
370
|
-
system: schema.String(),
|
|
371
|
-
key: schema.String()
|
|
372
|
-
}, optional),
|
|
373
|
-
fontSize: schema.Number(optional),
|
|
374
|
-
fontColor: schema.String(optional),
|
|
375
|
-
fontWeight: schema.Number(optional),
|
|
376
|
-
entranceAnimation: schema.String(optional),
|
|
377
|
-
entranceAnimationDurationMs: schema.Number(optional),
|
|
378
|
-
strokeColor: schema.String(optional),
|
|
379
|
-
strokeWidth: schema.Number(optional),
|
|
380
|
-
positionX: schema.Number(optional),
|
|
381
|
-
positionY: schema.Number(optional)
|
|
382
|
-
}, {
|
|
383
|
-
...optional,
|
|
384
|
-
...mergeable
|
|
385
|
-
})
|
|
386
|
-
}, mergeable)),
|
|
387
|
-
"voice-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
388
|
-
system: schema.String(),
|
|
389
|
-
key: schema.String(),
|
|
390
|
-
name: schema.String(optional)
|
|
391
|
-
}), mergeable),
|
|
392
|
-
"asset-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
393
|
-
system: schema.String(),
|
|
394
|
-
key: schema.String(),
|
|
395
|
-
storageKey: schema.String(optional),
|
|
396
|
-
digest: schema.String(optional)
|
|
397
|
-
}), mergeable),
|
|
398
|
-
"contain-relations": schema.LoroTree(schema.LoroMap({ entityId: schema.String() })),
|
|
399
|
-
"clip-source-relations": relation(["clipId", "sourceId"]),
|
|
400
|
-
"time-anchor-relations": atomic(timeAnchorCodec),
|
|
401
|
-
"caption-content-relations": atomic(captionContentCodec),
|
|
402
|
-
"caption-alignment-relations": schema.LoroMapRecord(schema.LoroMap({
|
|
403
|
-
captionId: schema.String(),
|
|
404
|
-
mediaId: schema.String(),
|
|
405
|
-
startMs: schema.Number(),
|
|
406
|
-
endMs: schema.Number()
|
|
407
|
-
}), mergeable),
|
|
408
|
-
"voice-timbre-relations": relation(["recordingId", "voiceId"]),
|
|
409
|
-
"derived-from-relations": relation(["entityId", "sourceId"]),
|
|
410
|
-
"from-asset-relations": relation(["audioScriptId", "assetId"]),
|
|
411
|
-
"to-asset-relations": relation(["audioScriptId", "assetId"])
|
|
412
|
-
});
|
|
413
|
-
//#endregion
|
|
414
|
-
//#region ../medeo-dsl/src/schema/document-format.ts
|
|
415
|
-
/** Format discrimination does not register containers or alter the document. */
|
|
416
|
-
function documentFormat(doc) {
|
|
417
|
-
const roots = doc.getShallowValue();
|
|
418
|
-
const legacy = [
|
|
419
|
-
"medeo",
|
|
420
|
-
"timeline",
|
|
421
|
-
"tracks",
|
|
422
|
-
"part_library"
|
|
423
|
-
].some((key) => Object.hasOwn(roots, key));
|
|
424
|
-
const dsl = Object.keys(roots).some((key) => key.endsWith("-entities") || key.endsWith("-relations"));
|
|
425
|
-
return legacy && dsl ? "mixed" : legacy ? "legacy" : dsl ? "dsl" : "unknown";
|
|
426
|
-
}
|
|
427
|
-
var UnsupportedDocumentFormatError = class extends Error {
|
|
428
|
-
code = "unsupported_document_format";
|
|
429
|
-
constructor() {
|
|
430
|
-
super("Expected a new DSL document; legacy, mixed or uninitialized content is not supported");
|
|
431
|
-
this.name = "UnsupportedDocumentFormatError";
|
|
432
|
-
}
|
|
433
|
-
};
|
|
434
|
-
/** Run after initial import, before opening an editable handle. Empty new documents still have one Timeline. */
|
|
435
|
-
function assertDslDocument(doc) {
|
|
436
|
-
if (documentFormat(doc) !== "dsl" || doc.getMap("timeline-entities").keys().length !== 1) throw new UnsupportedDocumentFormatError();
|
|
437
|
-
}
|
|
438
|
-
//#endregion
|
|
439
|
-
//#region ../medeo-dsl/src/schema/text-styles.ts
|
|
440
|
-
/** How rich-text marks extend at their edges: a language runs on into new text, a pause stays on its space. */
|
|
441
|
-
const textStyles = {
|
|
442
|
-
language: { expand: "after" },
|
|
443
|
-
pauseMs: { expand: "none" }
|
|
444
|
-
};
|
|
445
|
-
//#endregion
|
|
446
|
-
//#region src/dsl/projection/video-draft-types.ts
|
|
447
|
-
const DEFAULT_UNIT_TIME_MS = 33.333;
|
|
448
|
-
//#endregion
|
|
449
|
-
export { resourceId as C, relationId as S, relationTables as _, documentFormat as a, assertResourceIdentity as b, isInvalidAtomic as c, assertEntityPatch as d, assertId as f, mergeFields as g, isRecord as h, assertDslDocument as i, timeAnchorCodec as l, entityTables as m, textStyles as n, medeoDslLoroShape as o, assertRelation as p, UnsupportedDocumentFormatError as r, captionContentCodec as s, DEFAULT_UNIT_TIME_MS as t, assertEntity as u, validLanguage as v, tupleHash as w, defaultIdFactory as x, assertRelationIdentity as y };
|