@mengine/medeo-client 2.1.1-dsl.2 → 2.1.1-dsl.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 +13 -12
- package/dist/{dsl-EV6kCdr6.js → dsl-B7-4dMjr.js} +1125 -531
- package/dist/dsl.d.ts +3 -3
- package/dist/dsl.js +3 -3
- package/dist/{index-D-6uebu4.d.ts → index-CcNkkQll.d.ts} +59 -56
- package/dist/{index-D-3rdfUP.d.ts → index-D4Bgukns.d.ts} +1 -1
- package/dist/{index-Cu7SdKN5.d.ts → index-DVmvFhEn.d.ts} +208 -171
- package/dist/index.d.ts +5 -5
- package/dist/index.js +13 -7
- 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-c_shaRyq.d.ts → video-draft-types-0J2vfXBu.d.ts} +128 -55
- package/dist/{video-draft-types-TXRv3wS6.js → video-draft-types-BfIXM8q3.js} +215 -115
- package/package.json +4 -4
|
@@ -21,29 +21,22 @@ function resourceId(kind, system, key) {
|
|
|
21
21
|
function relationId(table, value) {
|
|
22
22
|
const v = value;
|
|
23
23
|
switch (table) {
|
|
24
|
-
case "clip-source-relations": return `cs:${v.clipId}`;
|
|
25
|
-
case "time-anchor-relations": return `ta:${v.from}`;
|
|
26
|
-
case "caption-content-relations": return `cc:${v.captionId}`;
|
|
27
|
-
case "caption-alignment-relations": return `ca:${v.captionId}`;
|
|
28
24
|
case "voice-timbre-relations": return `voice-timbre:${tupleHash([v.recordingId, v.voiceId])}`;
|
|
29
25
|
case "derived-from-relations": return `derived-from:${tupleHash([v.entityId, v.sourceId])}`;
|
|
30
|
-
case "from-asset-relations": return `from-asset:${v.audioScriptId}`;
|
|
31
|
-
case "to-asset-relations": return `to-asset:${v.audioScriptId}`;
|
|
32
26
|
}
|
|
33
27
|
throw new Error(`Unknown relation table: ${table}`);
|
|
34
28
|
}
|
|
35
29
|
const defaultIdFactory = (kind) => `${kind}_${globalThis.crypto.randomUUID()}`;
|
|
36
30
|
const resourceKinds = {
|
|
37
31
|
"media-entities": "media",
|
|
38
|
-
"voice-entities": "voice"
|
|
39
|
-
"asset-entities": "asset"
|
|
32
|
+
"voice-entities": "voice"
|
|
40
33
|
};
|
|
41
34
|
/** A resource row's ID is derived from its locator, so one external resource is one entity. */
|
|
42
35
|
function assertResourceIdentity(table, id, value) {
|
|
43
36
|
const kind = resourceKinds[table];
|
|
44
37
|
if (kind && id !== resourceId(kind, value.system, value.key)) throw new Error("Resource identity does not match locator");
|
|
45
38
|
}
|
|
46
|
-
/** A relation row's ID is derived from its
|
|
39
|
+
/** A relation row's ID is derived from its two ends. */
|
|
47
40
|
function assertRelationIdentity(table, id, value) {
|
|
48
41
|
if (id !== relationId(table, value)) throw new Error("Relation ID does not match endpoints");
|
|
49
42
|
}
|
|
@@ -52,6 +45,7 @@ function assertRelationIdentity(table, id, value) {
|
|
|
52
45
|
const string = (v) => typeof v === "string";
|
|
53
46
|
const nonempty = (v) => string(v) && v.length > 0;
|
|
54
47
|
const finite = (v) => typeof v === "number" && Number.isFinite(v);
|
|
48
|
+
const fraction = (v) => finite(v) && v >= 0 && v <= 1;
|
|
55
49
|
const integer = (v) => typeof v === "number" && Number.isSafeInteger(v);
|
|
56
50
|
const nonnegative = (v) => integer(v) && v >= 0;
|
|
57
51
|
const positive = (v) => integer(v) && v > 0;
|
|
@@ -61,16 +55,19 @@ const optional$1 = (check) => ({
|
|
|
61
55
|
check,
|
|
62
56
|
optional: true
|
|
63
57
|
});
|
|
58
|
+
const reservedIds = [
|
|
59
|
+
"$cid",
|
|
60
|
+
"__proto__",
|
|
61
|
+
"constructor",
|
|
62
|
+
"prototype"
|
|
63
|
+
];
|
|
64
|
+
const id = (v) => nonempty(v) && !reservedIds.includes(v);
|
|
65
|
+
const cursor = (v) => v instanceof Cursor;
|
|
64
66
|
function isRecord(value) {
|
|
65
67
|
return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Cursor);
|
|
66
68
|
}
|
|
67
69
|
function assertId(value) {
|
|
68
|
-
if (!
|
|
69
|
-
"$cid",
|
|
70
|
-
"__proto__",
|
|
71
|
-
"constructor",
|
|
72
|
-
"prototype"
|
|
73
|
-
].includes(value)) throw new Error("Expected a nonempty, non-reserved ID");
|
|
70
|
+
if (!id(value)) throw new Error("Expected a nonempty, non-reserved ID");
|
|
74
71
|
}
|
|
75
72
|
function validLanguage(value) {
|
|
76
73
|
if (typeof value !== "string") return false;
|
|
@@ -113,8 +110,8 @@ const styleFields = {
|
|
|
113
110
|
entranceAnimationDurationMs: optional$1(nonnegative),
|
|
114
111
|
strokeColor: optional$1(string),
|
|
115
112
|
strokeWidth: optional$1(finite),
|
|
116
|
-
positionX: optional$1(
|
|
117
|
-
positionY: optional$1(
|
|
113
|
+
positionX: optional$1(fraction),
|
|
114
|
+
positionY: optional$1(fraction)
|
|
118
115
|
};
|
|
119
116
|
const seqMarkerFields = {
|
|
120
117
|
inMs: required(nonnegative),
|
|
@@ -126,6 +123,51 @@ const seqMarkerFields = {
|
|
|
126
123
|
function assertSeqMarker(value) {
|
|
127
124
|
checkFields(value, seqMarkerFields);
|
|
128
125
|
}
|
|
126
|
+
const timeAnchorFields = {
|
|
127
|
+
to: required(id),
|
|
128
|
+
offsetMs: required(integer),
|
|
129
|
+
fallback_abs_ms: required(nonnegative)
|
|
130
|
+
};
|
|
131
|
+
/** A time anchor's own fields; what it points at is checked by `assertReferenceAdmitted`. */
|
|
132
|
+
function assertTimeAnchor(value) {
|
|
133
|
+
checkFields(value, timeAnchorFields);
|
|
134
|
+
}
|
|
135
|
+
const selectionFields = {
|
|
136
|
+
audioScriptId: required(id),
|
|
137
|
+
segmentId: required(id),
|
|
138
|
+
start: optional$1(cursor),
|
|
139
|
+
end: optional$1(cursor)
|
|
140
|
+
};
|
|
141
|
+
/** A whole segment, or a run inside it: both ends or neither. */
|
|
142
|
+
const segmentSelection = (fields) => (v) => object(fields)(v) && v.start === void 0 === (v.end === void 0);
|
|
143
|
+
function assertCaptionContent(value) {
|
|
144
|
+
if (!segmentSelection(selectionFields)(value)) throw new Error("Invalid segment selection");
|
|
145
|
+
}
|
|
146
|
+
const phonemeFields = {
|
|
147
|
+
...selectionFields,
|
|
148
|
+
phonemeScript: optional$1(string)
|
|
149
|
+
};
|
|
150
|
+
function assertPhoneme(value) {
|
|
151
|
+
if (!segmentSelection(phonemeFields)(value)) throw new Error("Invalid phoneme");
|
|
152
|
+
}
|
|
153
|
+
const segmentFields = {
|
|
154
|
+
id: required(id),
|
|
155
|
+
text: required(string),
|
|
156
|
+
startMs: optional$1(nonnegative),
|
|
157
|
+
endMs: optional$1(nonnegative)
|
|
158
|
+
};
|
|
159
|
+
/** A segment's time in the medium it was read off: both ends or neither, the end not before the start. */
|
|
160
|
+
const segment = (v) => {
|
|
161
|
+
if (!object(segmentFields)(v)) return false;
|
|
162
|
+
const { startMs, endMs } = v;
|
|
163
|
+
return startMs === void 0 ? endMs === void 0 : endMs !== void 0 && endMs >= startMs;
|
|
164
|
+
};
|
|
165
|
+
/** One segment as a script stores it; a segment added on its own is checked here, not with its row. */
|
|
166
|
+
function assertScriptSegment(value) {
|
|
167
|
+
if (!segment(value)) throw new Error("A segment is { id, text } with startMs and endMs both or neither, endMs not before startMs");
|
|
168
|
+
}
|
|
169
|
+
/** A script's segments: each with its own id, unique within the script. */
|
|
170
|
+
const segments = (v) => Array.isArray(v) && v.every(segment) && new Set(v.map((s) => s.id)).size === v.length;
|
|
129
171
|
const locator = {
|
|
130
172
|
system: required(oneOf("memota", "memota-speech")),
|
|
131
173
|
key: required(nonempty)
|
|
@@ -138,7 +180,9 @@ const entityFields = {
|
|
|
138
180
|
},
|
|
139
181
|
"clip-entities": {
|
|
140
182
|
seqMarker: required(object(seqMarkerFields)),
|
|
141
|
-
volume: optional$1(finite)
|
|
183
|
+
volume: optional$1(finite),
|
|
184
|
+
source: required(id),
|
|
185
|
+
anchor: optional$1(object(timeAnchorFields))
|
|
142
186
|
},
|
|
143
187
|
"media-entities": {
|
|
144
188
|
...locator,
|
|
@@ -148,10 +192,22 @@ const entityFields = {
|
|
|
148
192
|
digest: optional$1(nonempty)
|
|
149
193
|
},
|
|
150
194
|
"audio-script-entities": {
|
|
151
|
-
|
|
152
|
-
defaultLanguage: optional$1(validLanguage)
|
|
195
|
+
segments: required(segments),
|
|
196
|
+
defaultLanguage: optional$1(validLanguage),
|
|
197
|
+
system: optional$1(oneOf("memota")),
|
|
198
|
+
key: optional$1(nonempty),
|
|
199
|
+
storageKey: optional$1(nonempty),
|
|
200
|
+
digest: optional$1(nonempty)
|
|
201
|
+
},
|
|
202
|
+
"phonetic-script-entities": {
|
|
203
|
+
phoneme: optional$1(segmentSelection(phonemeFields)),
|
|
204
|
+
system: optional$1(oneOf("memota")),
|
|
205
|
+
key: optional$1(nonempty),
|
|
206
|
+
storageKey: optional$1(nonempty),
|
|
207
|
+
digest: optional$1(nonempty)
|
|
153
208
|
},
|
|
154
209
|
"caption-entities": {
|
|
210
|
+
selection: optional$1(segmentSelection(selectionFields)),
|
|
155
211
|
text: optional$1(string),
|
|
156
212
|
style: optional$1(object(styleFields))
|
|
157
213
|
},
|
|
@@ -159,57 +215,57 @@ const entityFields = {
|
|
|
159
215
|
system: required(oneOf("voice-library")),
|
|
160
216
|
key: required(nonempty),
|
|
161
217
|
name: optional$1(string)
|
|
162
|
-
},
|
|
163
|
-
"asset-entities": {
|
|
164
|
-
...locator,
|
|
165
|
-
storageKey: optional$1(nonempty),
|
|
166
|
-
digest: optional$1(nonempty)
|
|
167
218
|
}
|
|
168
219
|
};
|
|
169
220
|
const entityTables = Object.keys(entityFields);
|
|
221
|
+
/**
|
|
222
|
+
* Fields stored as one encoded string: written whole, never merged field by field. A patch to one
|
|
223
|
+
* is merged into the current value first, then the whole value is written.
|
|
224
|
+
*/
|
|
225
|
+
const atomicFields = {
|
|
226
|
+
"clip-entities": ["seqMarker", "anchor"],
|
|
227
|
+
"phonetic-script-entities": ["phoneme"],
|
|
228
|
+
"caption-entities": ["selection"]
|
|
229
|
+
};
|
|
170
230
|
const relationFields = {
|
|
171
|
-
"clip-source-relations": {
|
|
172
|
-
clipId: required(nonempty),
|
|
173
|
-
sourceId: required(nonempty)
|
|
174
|
-
},
|
|
175
|
-
"time-anchor-relations": {
|
|
176
|
-
from: required(nonempty),
|
|
177
|
-
to: required(nonempty),
|
|
178
|
-
offsetMs: required(integer),
|
|
179
|
-
fallback_abs_ms: required(nonnegative)
|
|
180
|
-
},
|
|
181
|
-
"caption-content-relations": {
|
|
182
|
-
captionId: required(nonempty),
|
|
183
|
-
audioScriptId: required(nonempty),
|
|
184
|
-
start: required((v) => v instanceof Cursor),
|
|
185
|
-
end: required((v) => v instanceof Cursor)
|
|
186
|
-
},
|
|
187
|
-
"caption-alignment-relations": {
|
|
188
|
-
captionId: required(nonempty),
|
|
189
|
-
mediaId: required(nonempty),
|
|
190
|
-
startMs: required(nonnegative),
|
|
191
|
-
endMs: required(nonnegative)
|
|
192
|
-
},
|
|
193
231
|
"voice-timbre-relations": {
|
|
194
|
-
recordingId: required(
|
|
195
|
-
voiceId: required(
|
|
232
|
+
recordingId: required(id),
|
|
233
|
+
voiceId: required(id)
|
|
196
234
|
},
|
|
197
235
|
"derived-from-relations": {
|
|
198
|
-
entityId: required(
|
|
199
|
-
sourceId: required(
|
|
200
|
-
|
|
201
|
-
"from-asset-relations": {
|
|
202
|
-
audioScriptId: required(nonempty),
|
|
203
|
-
assetId: required(nonempty)
|
|
204
|
-
},
|
|
205
|
-
"to-asset-relations": {
|
|
206
|
-
audioScriptId: required(nonempty),
|
|
207
|
-
assetId: required(nonempty)
|
|
236
|
+
entityId: required(id),
|
|
237
|
+
sourceId: required(id),
|
|
238
|
+
sourceDigest: optional$1(nonempty)
|
|
208
239
|
}
|
|
209
240
|
};
|
|
210
241
|
const relationTables = Object.keys(relationFields);
|
|
242
|
+
const fileFields = [
|
|
243
|
+
"system",
|
|
244
|
+
"key",
|
|
245
|
+
"storageKey",
|
|
246
|
+
"digest"
|
|
247
|
+
];
|
|
248
|
+
const phonemeScriptOf = (row) => isRecord(row.phoneme) ? row.phoneme.phonemeScript : void 0;
|
|
249
|
+
/**
|
|
250
|
+
* A PhoneticScript as a write leaves it: written for a segment (D181), and its phonemeScript is raw
|
|
251
|
+
* content stored as its file (D178) — with text the row names that file and its digest, without
|
|
252
|
+
* text it has no file, and rewritten text is a new file.
|
|
253
|
+
*/
|
|
254
|
+
function assertPhoneticScript(before, after) {
|
|
255
|
+
if (!isRecord(after.phoneme)) throw new Error("A PhoneticScript is written for a segment of its base script");
|
|
256
|
+
if (phonemeScriptOf(after) === void 0) {
|
|
257
|
+
if (fileFields.some((field) => after[field] !== void 0)) throw new Error("A PhoneticScript without text has no file");
|
|
258
|
+
} else if (after.system === void 0 || after.key === void 0 || after.digest === void 0) throw new Error("A PhoneticScript stores its phonemeScript as a file: name it by system and key with its digest");
|
|
259
|
+
if (before !== void 0 && phonemeScriptOf(after) !== phonemeScriptOf(before) && after.digest !== void 0 && after.digest === before.digest) throw new Error("A rewritten phonemeScript is stored again: write its new file");
|
|
260
|
+
}
|
|
261
|
+
/** A transcript names the file it was read from by system and key together; its facts come with that name. */
|
|
262
|
+
function assertTranscriptFile(row) {
|
|
263
|
+
if (row.system === void 0 !== (row.key === void 0)) throw new Error("A transcript names its transcription file by system and key");
|
|
264
|
+
if (row.key === void 0 && (row.storageKey !== void 0 || row.digest !== void 0)) throw new Error("A script without a transcription file has no file facts");
|
|
265
|
+
}
|
|
211
266
|
function assertEntity(table, value) {
|
|
212
267
|
checkFields(value, entityFields[table]);
|
|
268
|
+
if (table === "audio-script-entities") assertTranscriptFile(value);
|
|
213
269
|
if (table === "media-entities") {
|
|
214
270
|
if (value.kind === "image" && value.durationMs !== void 0) throw new Error("Image has no intrinsic duration");
|
|
215
271
|
if (value.kind !== "image" && !positive(value.durationMs)) throw new Error("Finite media requires durationMs");
|
|
@@ -219,15 +275,19 @@ function assertEntity(table, value) {
|
|
|
219
275
|
/** Validate only touched fields, so an unrelated edit can proceed in a merged, invalid document. */
|
|
220
276
|
function assertEntityPatch(table, patch, current) {
|
|
221
277
|
if (!isRecord(patch)) throw new Error("Expected an entity patch");
|
|
222
|
-
if (table === "audio-script-entities" && Object.hasOwn(patch, "
|
|
278
|
+
if (table === "audio-script-entities" && Object.hasOwn(patch, "segments")) throw new Error("Change segments with segment mutations and edit their text through the Text adapter");
|
|
223
279
|
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");
|
|
224
280
|
if (table === "caption-entities" && current.text !== void 0 && patch.text !== void 0) throw new Error("Edit Caption text through the Text adapter");
|
|
225
|
-
const next =
|
|
281
|
+
const next = patchRow(table, current, patch);
|
|
226
282
|
for (const key of Object.keys(patch)) {
|
|
227
283
|
const field = entityFields[table][key];
|
|
228
284
|
if (!field || !field.optional && next[key] === void 0 || next[key] !== void 0 && !field.check(next[key])) throw new Error(`Invalid patch field: ${key}`);
|
|
229
285
|
}
|
|
230
|
-
if (table === "
|
|
286
|
+
if (table === "audio-script-entities" && fileFields.some((field) => Object.hasOwn(patch, field))) {
|
|
287
|
+
if (current.key !== void 0 && (next.system !== current.system || next.key !== current.key)) throw new Error("A transcript's transcription file is fixed once named");
|
|
288
|
+
assertTranscriptFile(next);
|
|
289
|
+
}
|
|
290
|
+
if (table === "media-entities" || table === "voice-entities") {
|
|
231
291
|
for (const key of [
|
|
232
292
|
"system",
|
|
233
293
|
"key",
|
|
@@ -243,18 +303,25 @@ function assertEntityPatch(table, patch, current) {
|
|
|
243
303
|
}
|
|
244
304
|
function assertRelation(table, value) {
|
|
245
305
|
checkFields(value, relationFields[table]);
|
|
246
|
-
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* The row after a patch. An atomic field merges into its current value, so a partial patch keeps
|
|
309
|
+
* the rest of it; an unreadable stored value is replaced instead, so writing a whole value repairs it.
|
|
310
|
+
*/
|
|
311
|
+
function patchRow(table, current, patch) {
|
|
312
|
+
const next = mergeFields(current, patch);
|
|
313
|
+
for (const key of atomicFields[table] ?? []) {
|
|
314
|
+
const old = current[key];
|
|
315
|
+
const value = patch[key];
|
|
316
|
+
if (value !== void 0 && isRecord(old) && old.invalid === true) next[key] = isRecord(value) ? mergeFields({}, value) : value;
|
|
317
|
+
}
|
|
318
|
+
return next;
|
|
247
319
|
}
|
|
248
320
|
/** Undefined deletes; nested patches retain sibling fields and an existing empty style Map. */
|
|
249
321
|
function mergeFields(target, patch) {
|
|
250
322
|
const result = { ...target };
|
|
251
323
|
for (const [key, value] of Object.entries(patch)) {
|
|
252
|
-
if (
|
|
253
|
-
"$cid",
|
|
254
|
-
"__proto__",
|
|
255
|
-
"constructor",
|
|
256
|
-
"prototype"
|
|
257
|
-
].includes(key)) throw new Error(`Reserved field: ${key}`);
|
|
324
|
+
if (reservedIds.includes(key)) throw new Error(`Reserved field: ${key}`);
|
|
258
325
|
if (value === void 0) delete result[key];
|
|
259
326
|
else result[key] = isRecord(value) ? mergeFields(isRecord(result[key]) ? result[key] : {}, value) : value;
|
|
260
327
|
}
|
|
@@ -1252,36 +1319,60 @@ function codec(encode, decode) {
|
|
|
1252
1319
|
}
|
|
1253
1320
|
};
|
|
1254
1321
|
}
|
|
1322
|
+
/** A Clip's time anchor; the Clip holding it is the anchored end. */
|
|
1255
1323
|
const timeAnchorCodec = codec((v) => {
|
|
1256
|
-
|
|
1324
|
+
assertTimeAnchor(v);
|
|
1257
1325
|
return JSON.stringify({
|
|
1258
|
-
from: v.from,
|
|
1259
1326
|
to: v.to,
|
|
1260
1327
|
offsetMs: v.offsetMs,
|
|
1261
1328
|
fallback_abs_ms: v.fallback_abs_ms
|
|
1262
1329
|
});
|
|
1263
1330
|
}, (raw) => {
|
|
1264
1331
|
const v = JSON.parse(raw);
|
|
1265
|
-
|
|
1332
|
+
assertTimeAnchor(v);
|
|
1266
1333
|
return v;
|
|
1267
1334
|
});
|
|
1335
|
+
/** A segment selection as stored: a run's Cursors as their native bytes in unpadded base64url. */
|
|
1336
|
+
function encodeSelection(v) {
|
|
1337
|
+
return {
|
|
1338
|
+
audioScriptId: v.audioScriptId,
|
|
1339
|
+
segmentId: v.segmentId,
|
|
1340
|
+
...v.start === void 0 || v.end === void 0 ? {} : {
|
|
1341
|
+
start: bytesToBase64url(v.start.encode()),
|
|
1342
|
+
end: bytesToBase64url(v.end.encode())
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
function decodeSelection(v) {
|
|
1347
|
+
if (!v || typeof v !== "object") throw new Error("Expected a segment selection");
|
|
1348
|
+
const { start, end, ...rest } = v;
|
|
1349
|
+
if (start === void 0 && end === void 0) return rest;
|
|
1350
|
+
if (typeof start !== "string" || typeof end !== "string") throw new Error("Expected encoded Cursor pair");
|
|
1351
|
+
return {
|
|
1352
|
+
...rest,
|
|
1353
|
+
start: Cursor.decode(base64urlToBytes(start)),
|
|
1354
|
+
end: Cursor.decode(base64urlToBytes(end))
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
/** A Caption's selection. */
|
|
1268
1358
|
const captionContentCodec = codec((v) => {
|
|
1269
|
-
|
|
1359
|
+
assertCaptionContent(v);
|
|
1360
|
+
return JSON.stringify(encodeSelection(v));
|
|
1361
|
+
}, (raw) => {
|
|
1362
|
+
const value = decodeSelection(JSON.parse(raw));
|
|
1363
|
+
assertCaptionContent(value);
|
|
1364
|
+
return value;
|
|
1365
|
+
});
|
|
1366
|
+
/** A PhoneticScript's selection and what to synthesize for it, stored as one string so they move together. */
|
|
1367
|
+
const phonemeCodec = codec((v) => {
|
|
1368
|
+
assertPhoneme(v);
|
|
1270
1369
|
return JSON.stringify({
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
start: bytesToBase64url(v.start.encode()),
|
|
1274
|
-
end: bytesToBase64url(v.end.encode())
|
|
1370
|
+
...encodeSelection(v),
|
|
1371
|
+
...v.phonemeScript === void 0 ? {} : { phonemeScript: v.phonemeScript }
|
|
1275
1372
|
});
|
|
1276
1373
|
}, (raw) => {
|
|
1277
|
-
const
|
|
1278
|
-
|
|
1279
|
-
const value = {
|
|
1280
|
-
...v,
|
|
1281
|
-
start: Cursor.decode(base64urlToBytes(v.start)),
|
|
1282
|
-
end: Cursor.decode(base64urlToBytes(v.end))
|
|
1283
|
-
};
|
|
1284
|
-
assertRelation("caption-content-relations", value);
|
|
1374
|
+
const value = decodeSelection(JSON.parse(raw));
|
|
1375
|
+
assertPhoneme(value);
|
|
1285
1376
|
return value;
|
|
1286
1377
|
});
|
|
1287
1378
|
/** A Clip's sequence marker is stored as one string, so it is taken or replaced whole. */
|
|
@@ -1304,13 +1395,19 @@ const optional = { required: false };
|
|
|
1304
1395
|
const mergeable = { mergeableMapChildContainers: true };
|
|
1305
1396
|
const strings = (keys) => Object.fromEntries(keys.map((key) => [key, schema.String()]));
|
|
1306
1397
|
const relation = (keys) => schema.LoroMapRecord(schema.LoroMap(strings(keys)), mergeable);
|
|
1307
|
-
const
|
|
1398
|
+
const transform = (codec) => ({
|
|
1308
1399
|
...codec,
|
|
1309
1400
|
isEqual: "encoded-value-equality",
|
|
1310
1401
|
validateEncodedType: true
|
|
1311
1402
|
});
|
|
1312
|
-
|
|
1313
|
-
|
|
1403
|
+
/** One field stored as one encoded string, so it is taken or replaced whole. */
|
|
1404
|
+
const atomicValue = (codec) => schema.String().transform(transform(codec));
|
|
1405
|
+
const optionalAtomicValue = (codec) => schema.String(optional).transform(transform(codec));
|
|
1406
|
+
/**
|
|
1407
|
+
* Only direct children inherit mergeable identity. Text and ordinary entity rows keep normal
|
|
1408
|
+
* identities, so deleting a row also drops what a peer wrote into it concurrently: a relation an
|
|
1409
|
+
* entity holds at most one of is a field of that row and never outlives it.
|
|
1410
|
+
*/
|
|
1314
1411
|
const medeoDslLoroShape = schema({
|
|
1315
1412
|
"timeline-entities": schema.LoroMapRecord(schema.LoroMap({})),
|
|
1316
1413
|
"track-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
@@ -1319,7 +1416,9 @@ const medeoDslLoroShape = schema({
|
|
|
1319
1416
|
})),
|
|
1320
1417
|
"clip-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
1321
1418
|
seqMarker: atomicValue(seqMarkerCodec),
|
|
1322
|
-
volume: schema.Number(optional)
|
|
1419
|
+
volume: schema.Number(optional),
|
|
1420
|
+
source: schema.String(),
|
|
1421
|
+
anchor: optionalAtomicValue(timeAnchorCodec)
|
|
1323
1422
|
})),
|
|
1324
1423
|
"media-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
1325
1424
|
kind: schema.String(),
|
|
@@ -1330,10 +1429,27 @@ const medeoDslLoroShape = schema({
|
|
|
1330
1429
|
digest: schema.String(optional)
|
|
1331
1430
|
}), mergeable),
|
|
1332
1431
|
"audio-script-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
1333
|
-
|
|
1334
|
-
|
|
1432
|
+
segments: schema.LoroMovableList(schema.LoroMap({
|
|
1433
|
+
id: schema.String(),
|
|
1434
|
+
text: schema.LoroText(),
|
|
1435
|
+
startMs: schema.Number(optional),
|
|
1436
|
+
endMs: schema.Number(optional)
|
|
1437
|
+
}), (segment) => segment.id),
|
|
1438
|
+
defaultLanguage: schema.String(optional),
|
|
1439
|
+
system: schema.String(optional),
|
|
1440
|
+
key: schema.String(optional),
|
|
1441
|
+
storageKey: schema.String(optional),
|
|
1442
|
+
digest: schema.String(optional)
|
|
1443
|
+
})),
|
|
1444
|
+
"phonetic-script-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
1445
|
+
phoneme: atomicValue(phonemeCodec),
|
|
1446
|
+
system: schema.String(optional),
|
|
1447
|
+
key: schema.String(optional),
|
|
1448
|
+
storageKey: schema.String(optional),
|
|
1449
|
+
digest: schema.String(optional)
|
|
1335
1450
|
})),
|
|
1336
1451
|
"caption-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
1452
|
+
selection: optionalAtomicValue(captionContentCodec),
|
|
1337
1453
|
text: schema.LoroText(optional),
|
|
1338
1454
|
style: schema.LoroMap({
|
|
1339
1455
|
font: schema.LoroMap({
|
|
@@ -1359,26 +1475,13 @@ const medeoDslLoroShape = schema({
|
|
|
1359
1475
|
key: schema.String(),
|
|
1360
1476
|
name: schema.String(optional)
|
|
1361
1477
|
}), mergeable),
|
|
1362
|
-
"asset-entities": schema.LoroMapRecord(schema.LoroMap({
|
|
1363
|
-
system: schema.String(),
|
|
1364
|
-
key: schema.String(),
|
|
1365
|
-
storageKey: schema.String(optional),
|
|
1366
|
-
digest: schema.String(optional)
|
|
1367
|
-
}), mergeable),
|
|
1368
1478
|
"contain-relations": schema.LoroTree(schema.LoroMap({ entityId: schema.String() })),
|
|
1369
|
-
"clip-source-relations": relation(["clipId", "sourceId"]),
|
|
1370
|
-
"time-anchor-relations": atomic(timeAnchorCodec),
|
|
1371
|
-
"caption-content-relations": atomic(captionContentCodec),
|
|
1372
|
-
"caption-alignment-relations": schema.LoroMapRecord(schema.LoroMap({
|
|
1373
|
-
captionId: schema.String(),
|
|
1374
|
-
mediaId: schema.String(),
|
|
1375
|
-
startMs: schema.Number(),
|
|
1376
|
-
endMs: schema.Number()
|
|
1377
|
-
}), mergeable),
|
|
1378
1479
|
"voice-timbre-relations": relation(["recordingId", "voiceId"]),
|
|
1379
|
-
"derived-from-relations":
|
|
1380
|
-
|
|
1381
|
-
|
|
1480
|
+
"derived-from-relations": schema.LoroMapRecord(schema.LoroMap({
|
|
1481
|
+
entityId: schema.String(),
|
|
1482
|
+
sourceId: schema.String(),
|
|
1483
|
+
sourceDigest: schema.String(optional)
|
|
1484
|
+
}), mergeable)
|
|
1382
1485
|
});
|
|
1383
1486
|
//#endregion
|
|
1384
1487
|
//#region ../medeo-dsl/src/schema/document-format.ts
|
|
@@ -1407,13 +1510,10 @@ function assertDslDocument(doc) {
|
|
|
1407
1510
|
}
|
|
1408
1511
|
//#endregion
|
|
1409
1512
|
//#region ../medeo-dsl/src/schema/text-styles.ts
|
|
1410
|
-
/** How rich-text marks extend at their edges: a language runs on into
|
|
1411
|
-
const textStyles = {
|
|
1412
|
-
language: { expand: "after" },
|
|
1413
|
-
pauseMs: { expand: "none" }
|
|
1414
|
-
};
|
|
1513
|
+
/** How rich-text marks extend at their edges: a language runs on into text typed after it. */
|
|
1514
|
+
const textStyles = { language: { expand: "after" } };
|
|
1415
1515
|
//#endregion
|
|
1416
1516
|
//#region src/dsl/projection/video-draft-types.ts
|
|
1417
1517
|
const DEFAULT_UNIT_TIME_MS = 33.333;
|
|
1418
1518
|
//#endregion
|
|
1419
|
-
export {
|
|
1519
|
+
export { assertEntityPatch as $, getRootContainerByType as A, isValueOfContainerType as B, applyEncode as C, decodeNestedJsonValues as D, containerIdToContainerType as E, isArrayLike as F, tryUpdateToContainer as G, schemaToContainerType as H, isObject as I, getChildContainerSchema as J, valuesEqual as K, isObjectLike as L, hasTransform as M, inferContainerTypeFromValue as N, deepEqual as O, insertChildToMap as P, assertEntity as Q, isStateAndSchemaOfType as R, applyDecode as S, cidsEqual as T, stripUndefined as U, safeStringify as V, tryInferContainerType as W, getMapFieldSchema as X, getChildSchema as Y, assertCaptionContent as Z, isLoroMovableListSchema as _, resourceId as _t, documentFormat as a, assertTimeAnchor as at, schemaContainsIgnoreField as b, isInvalidAtomic as c, isRecord as ct, schema as d, relationTables as dt, assertId as et, getDefaultValue as f, validLanguage as ft, isLoroMapSchema as g, relationId as gt, isLoroListSchema as h, defaultIdFactory as ht, assertDslDocument as i, assertScriptSegment as it, hardenCidDescriptors as j, defineCidProperty as k, phonemeCodec as l, mergeFields as lt, isListLikeSchema as m, assertResourceIdentity as mt, textStyles as n, assertPhoneticScript as nt, medeoDslLoroShape as o, atomicFields as ot, isContainerSchema as p, assertRelationIdentity as pt, CID_KEY as q, UnsupportedDocumentFormatError as r, assertRelation as rt, captionContentCodec as s, entityTables as st, DEFAULT_UNIT_TIME_MS as t, assertPhoneme as tt, timeAnchorCodec as u, patchRow as ut, isLoroTreeSchema as v, tupleHash as vt, applySchemaToInferOptions as w, validateSchema as x, isRootSchemaType as y, isTreeID as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mengine/medeo-client",
|
|
3
|
-
"version": "2.1.1-dsl.
|
|
3
|
+
"version": "2.1.1-dsl.21",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"@noble/hashes": "^2.4.0",
|
|
30
30
|
"immer": "^10.2.0",
|
|
31
31
|
"zod": "^4.4.3",
|
|
32
|
-
"@mengine/storage": "2.1.1-dsl.
|
|
33
|
-
"@mengine/sync": "2.1.1-dsl.
|
|
34
|
-
"@mengine/utils": "2.1.1-dsl.
|
|
32
|
+
"@mengine/storage": "2.1.1-dsl.21",
|
|
33
|
+
"@mengine/sync": "2.1.1-dsl.21",
|
|
34
|
+
"@mengine/utils": "2.1.1-dsl.21"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^25.9.1",
|