@mengine/medeo-client 2.1.1-dsl.9 → 3.0.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.
@@ -1,6 +1,333 @@
1
- import { $ as assertEntityPatch, A as getRootContainerByType, B as isValueOfContainerType, C as applyEncode, D as decodeNestedJsonValues, E as containerIdToContainerType, F as isArrayLike, G as tryUpdateToContainer, H as schemaToContainerType, I as isObject, J as getChildContainerSchema, K as valuesEqual, L as isObjectLike, M as hasTransform, N as inferContainerTypeFromValue, O as deepEqual, P as insertChildToMap, Q as assertEntity, R as isStateAndSchemaOfType, S as applyDecode, T as cidsEqual, U as stripUndefined, V as safeStringify, W as tryInferContainerType, X as getMapFieldSchema, Y as getChildSchema, Z as assertCaptionContent, _ as isLoroMovableListSchema, at as atomicFields, b as schemaContainsIgnoreField, c as isInvalidAtomic, ct as mergeFields, d as schema, dt as validLanguage, et as assertId, f as getDefaultValue, ft as assertRelationIdentity, g as isLoroMapSchema, gt as resourceId, h as isLoroListSchema, ht as relationId, it as assertTimeAnchor, j as hardenCidDescriptors, k as defineCidProperty, l as phonemeCodec, lt as patchRow, m as isListLikeSchema, mt as defaultIdFactory, n as textStyles, nt as assertPhoneticScript, o as medeoDslLoroShape, ot as entityTables, p as isContainerSchema, pt as assertResourceIdentity, q as CID_KEY, rt as assertRelation, s as captionContentCodec, st as isRecord, t as DEFAULT_UNIT_TIME_MS, tt as assertPhoneme, ut as relationTables, v as isLoroTreeSchema, w as applySchemaToInferOptions, x as validateSchema, y as isRootSchemaType, z as isTreeID } from "./video-draft-types-BnbfWrBx.js";
1
+ import { sha256 } from "@noble/hashes/sha2.js";
2
2
  import { Cursor, LoroDoc, LoroList, LoroMap, LoroMovableList, LoroText, LoroTree, isContainer, isContainerId } from "loro-crdt";
3
- import { Immer, setAutoFreeze } from "immer";
3
+ //#region ../medeo-dsl/src/ids.ts
4
+ function bytesToBase64url(bytes) {
5
+ let binary = "";
6
+ for (const byte of bytes) binary += String.fromCharCode(byte);
7
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
8
+ }
9
+ function base64urlToBytes(value) {
10
+ if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1) throw new Error("Invalid base64url");
11
+ const bytes = Uint8Array.from(atob(value.replaceAll("-", "+").replaceAll("_", "/")), (c) => c.charCodeAt(0));
12
+ if (bytesToBase64url(bytes) !== value) throw new Error("Non-canonical base64url");
13
+ return bytes;
14
+ }
15
+ function tupleHash(tuple) {
16
+ return bytesToBase64url(sha256(new TextEncoder().encode(JSON.stringify(tuple))));
17
+ }
18
+ function resourceId(kind, system, key) {
19
+ return `${kind}:${tupleHash([system, key])}`;
20
+ }
21
+ function relationId(table, value) {
22
+ const v = value;
23
+ switch (table) {
24
+ case "voice-timbre-relations": return `voice-timbre:${tupleHash([v.recordingId, v.voiceId])}`;
25
+ case "derived-from-relations": return `derived-from:${tupleHash([v.entityId, v.sourceId])}`;
26
+ }
27
+ throw new Error(`Unknown relation table: ${table}`);
28
+ }
29
+ const defaultIdFactory = (kind) => `${kind}_${globalThis.crypto.randomUUID()}`;
30
+ const resourceKinds = {
31
+ "media-entities": "media",
32
+ "voice-entities": "voice"
33
+ };
34
+ /** A resource row's ID is derived from its locator, so one external resource is one entity. */
35
+ function assertResourceIdentity(table, id, value) {
36
+ const kind = resourceKinds[table];
37
+ if (kind && id !== resourceId(kind, value.system, value.key)) throw new Error("Resource identity does not match locator");
38
+ }
39
+ /** A relation row's ID is derived from its two ends. */
40
+ function assertRelationIdentity(table, id, value) {
41
+ if (id !== relationId(table, value)) throw new Error("Relation ID does not match endpoints");
42
+ }
43
+ //#endregion
44
+ //#region ../medeo-dsl/src/fields.ts
45
+ const string = (v) => typeof v === "string";
46
+ const nonempty = (v) => string(v) && v.length > 0;
47
+ const finite = (v) => typeof v === "number" && Number.isFinite(v);
48
+ const fraction = (v) => finite(v) && v >= 0 && v <= 1;
49
+ const integer = (v) => typeof v === "number" && Number.isSafeInteger(v);
50
+ const nonnegative = (v) => integer(v) && v >= 0;
51
+ const positive = (v) => integer(v) && v > 0;
52
+ const oneOf = (...values) => (v) => values.includes(v);
53
+ const required = (check) => ({ check });
54
+ const optional$1 = (check) => ({
55
+ check,
56
+ optional: true
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;
66
+ function isRecord(value) {
67
+ return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Cursor);
68
+ }
69
+ function assertId(value) {
70
+ if (!id(value)) throw new Error("Expected a nonempty, non-reserved ID");
71
+ }
72
+ function validLanguage(value) {
73
+ if (typeof value !== "string") return false;
74
+ if (/^x(?:-[a-z0-9]{1,8})+$/i.test(value)) return true;
75
+ try {
76
+ return value.length > 0 && Intl.getCanonicalLocales(value).length === 1;
77
+ } catch {
78
+ return false;
79
+ }
80
+ }
81
+ function object(fields) {
82
+ return (v) => {
83
+ try {
84
+ checkFields(v, fields);
85
+ return true;
86
+ } catch {
87
+ return false;
88
+ }
89
+ };
90
+ }
91
+ function checkFields(value, fields, partial = false) {
92
+ if (!isRecord(value)) throw new Error("Expected an object");
93
+ for (const key of Object.keys(value)) if (!Object.hasOwn(fields, key)) throw new Error(`Unknown field: ${key}`);
94
+ for (const [key, field] of Object.entries(fields)) {
95
+ if (partial && !Object.hasOwn(value, key)) continue;
96
+ const v = value[key];
97
+ if (v === void 0 && field.optional) continue;
98
+ if (!field.check(v)) throw new Error(`Invalid or missing field: ${key}`);
99
+ }
100
+ }
101
+ const styleFields = {
102
+ font: optional$1(object({
103
+ system: required(oneOf("font-library")),
104
+ key: required(nonempty)
105
+ })),
106
+ fontSize: optional$1(finite),
107
+ fontColor: optional$1(string),
108
+ fontWeight: optional$1(finite),
109
+ entranceAnimation: optional$1(string),
110
+ entranceAnimationDurationMs: optional$1(nonnegative),
111
+ strokeColor: optional$1(string),
112
+ strokeWidth: optional$1(finite),
113
+ positionX: optional$1(fraction),
114
+ positionY: optional$1(fraction)
115
+ };
116
+ const seqMarkerFields = {
117
+ inMs: required(nonnegative),
118
+ outMs: required(nonnegative),
119
+ rate: optional$1((v) => finite(v) && v > 0),
120
+ fillTimeline: optional$1(oneOf(true))
121
+ };
122
+ /** A sequence marker's own fields; the window being nonempty is checked where it is written. */
123
+ function assertSeqMarker(value) {
124
+ checkFields(value, seqMarkerFields);
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;
171
+ const locator = {
172
+ system: required(oneOf("memota", "memota-speech")),
173
+ key: required(nonempty)
174
+ };
175
+ const entityFields = {
176
+ "timeline-entities": {},
177
+ "track-entities": {
178
+ role: required(oneOf("video_clip", "speech", "caption", "bgm")),
179
+ hidden: optional$1((v) => typeof v === "boolean")
180
+ },
181
+ "clip-entities": {
182
+ seqMarker: required(object(seqMarkerFields)),
183
+ volume: optional$1(finite),
184
+ source: required(id),
185
+ anchor: optional$1(object(timeAnchorFields))
186
+ },
187
+ "media-entities": {
188
+ ...locator,
189
+ kind: required(oneOf("video", "audio", "voiceover-recording", "image")),
190
+ storageKey: optional$1(nonempty),
191
+ durationMs: optional$1(positive),
192
+ digest: optional$1(nonempty)
193
+ },
194
+ "audio-script-entities": {
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)
208
+ },
209
+ "caption-entities": {
210
+ selection: optional$1(segmentSelection(selectionFields)),
211
+ text: optional$1(string),
212
+ style: optional$1(object(styleFields))
213
+ },
214
+ "voice-entities": {
215
+ system: required(oneOf("voice-library")),
216
+ key: required(nonempty),
217
+ name: optional$1(string)
218
+ }
219
+ };
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
+ };
230
+ const relationFields = {
231
+ "voice-timbre-relations": {
232
+ recordingId: required(id),
233
+ voiceId: required(id)
234
+ },
235
+ "derived-from-relations": {
236
+ entityId: required(id),
237
+ sourceId: required(id),
238
+ sourceDigest: optional$1(nonempty)
239
+ }
240
+ };
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
+ }
266
+ function assertEntity(table, value) {
267
+ checkFields(value, entityFields[table]);
268
+ if (table === "audio-script-entities") assertTranscriptFile(value);
269
+ if (table === "media-entities") {
270
+ if (value.kind === "image" && value.durationMs !== void 0) throw new Error("Image has no intrinsic duration");
271
+ if (value.kind !== "image" && !positive(value.durationMs)) throw new Error("Finite media requires durationMs");
272
+ if (["audio", "voiceover-recording"].includes(value.kind) && !nonempty(value.storageKey)) throw new Error("Audio requires storageKey");
273
+ }
274
+ }
275
+ /** Validate only touched fields, so an unrelated edit can proceed in a merged, invalid document. */
276
+ function assertEntityPatch(table, patch, current) {
277
+ if (!isRecord(patch)) throw new Error("Expected an entity 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");
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");
280
+ if (table === "caption-entities" && current.text !== void 0 && patch.text !== void 0) throw new Error("Edit Caption text through the Text adapter");
281
+ const next = patchRow(table, current, patch);
282
+ for (const key of Object.keys(patch)) {
283
+ const field = entityFields[table][key];
284
+ if (!field || !field.optional && next[key] === void 0 || next[key] !== void 0 && !field.check(next[key])) throw new Error(`Invalid patch field: ${key}`);
285
+ }
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") {
291
+ for (const key of [
292
+ "system",
293
+ "key",
294
+ "kind"
295
+ ]) if (Object.hasOwn(patch, key) && patch[key] !== current[key]) throw new Error(`Resource identity field is immutable: ${key}`);
296
+ }
297
+ if (table === "media-entities") {
298
+ if (Object.hasOwn(patch, "durationMs")) {
299
+ if (next.kind === "image" ? next.durationMs !== void 0 : !positive(next.durationMs)) throw new Error("durationMs must match the media kind");
300
+ }
301
+ if (Object.hasOwn(patch, "storageKey") && ["audio", "voiceover-recording"].includes(next.kind) && !nonempty(next.storageKey)) throw new Error("Audio requires storageKey");
302
+ }
303
+ }
304
+ function assertRelation(table, value) {
305
+ checkFields(value, relationFields[table]);
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;
319
+ }
320
+ /** Undefined deletes; nested patches retain sibling fields and an existing empty style Map. */
321
+ function mergeFields(target, patch) {
322
+ const result = { ...target };
323
+ for (const [key, value] of Object.entries(patch)) {
324
+ if (reservedIds.includes(key)) throw new Error(`Reserved field: ${key}`);
325
+ if (value === void 0) delete result[key];
326
+ else result[key] = isRecord(value) ? mergeFields(isRecord(result[key]) ? result[key] : {}, value) : value;
327
+ }
328
+ return result;
329
+ }
330
+ //#endregion
4
331
  //#region ../medeo-dsl/src/text.ts
5
332
  function assertTextOffset(text, at) {
6
333
  if (!Number.isSafeInteger(at) || at < 0 || at > text.length) throw new Error("Invalid UTF-16 text offset");
@@ -896,12 +1223,1549 @@ function replaceSourcePlan(s, clipId, input) {
896
1223
  }
897
1224
  }];
898
1225
  }
899
- const produce = new Immer({
1226
+ //#endregion
1227
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/schema/resolver.js
1228
+ function getMapFieldSchema(schema, key) {
1229
+ if (!schema) return void 0;
1230
+ if (Object.prototype.hasOwnProperty.call(schema.definition, key)) return schema.definition[key];
1231
+ if (schema.type === "loro-map" && "catchallType" in schema) return schema.catchallType;
1232
+ }
1233
+ function getChildSchema(schema, childKey) {
1234
+ if (!schema) return void 0;
1235
+ switch (schema.type) {
1236
+ case "schema":
1237
+ case "loro-map": return childKey === void 0 ? void 0 : getMapFieldSchema(schema, String(childKey));
1238
+ case "loro-list":
1239
+ case "loro-movable-list": return schema.itemSchema;
1240
+ case "loro-tree": return schema.nodeSchema;
1241
+ default: return;
1242
+ }
1243
+ }
1244
+ function getChildContainerSchema(schema, childKey) {
1245
+ const childSchema = getChildSchema(schema, childKey);
1246
+ if (!childSchema) return void 0;
1247
+ switch (childSchema.type) {
1248
+ case "loro-map":
1249
+ case "loro-list":
1250
+ case "loro-movable-list":
1251
+ case "loro-text":
1252
+ case "loro-tree": return childSchema;
1253
+ default: return;
1254
+ }
1255
+ }
1256
+ //#endregion
1257
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/constants.js
1258
+ const CID_KEY = "$cid";
1259
+ //#endregion
1260
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/core/container-inference.js
1261
+ function isPlainObjectValue(value) {
1262
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp) && typeof value !== "function";
1263
+ }
1264
+ function inferContainerTypeFromValue$1(value, defaults) {
1265
+ switch (getContainerValueKind(value)) {
1266
+ case "map": return "Map";
1267
+ case "array": return defaults?.defaultMovableList ? "MovableList" : "List";
1268
+ case "string": return defaults?.defaultLoroText ? "Text" : void 0;
1269
+ default: return;
1270
+ }
1271
+ }
1272
+ function inferSchemaContainerTypeFromValue(value, defaults) {
1273
+ switch (inferContainerTypeFromValue$1(value, defaults)) {
1274
+ case "Map": return "loro-map";
1275
+ case "List": return "loro-list";
1276
+ case "MovableList": return "loro-movable-list";
1277
+ case "Text": return "loro-text";
1278
+ default: return;
1279
+ }
1280
+ }
1281
+ function matchesContainerType(containerType, value) {
1282
+ const kind = getContainerValueKind(value);
1283
+ switch (containerType) {
1284
+ case "Map": return kind === "map";
1285
+ case "List":
1286
+ case "MovableList":
1287
+ case "Tree": return kind === "array";
1288
+ case "Text": return kind === "string";
1289
+ default: return false;
1290
+ }
1291
+ }
1292
+ function getContainerValueKind(value) {
1293
+ if (isPlainObjectValue(value)) return "map";
1294
+ if (Array.isArray(value)) return "array";
1295
+ if (typeof value === "string") return "string";
1296
+ return "other";
1297
+ }
1298
+ //#endregion
1299
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/core/utils.js
1300
+ /**
1301
+ * Utility functions for Loro Mirror core
1302
+ */
1303
+ /**
1304
+ * Check if a schema has a transform.
1305
+ * Distinguishes between the .transform() builder method (function) and an actual
1306
+ * TransformDefinition object (with decode/encode functions).
1307
+ */
1308
+ function hasTransform(schema) {
1309
+ if (schema === void 0) return false;
1310
+ const t = schema.transform;
1311
+ return t != null && typeof t === "object";
1312
+ }
1313
+ /**
1314
+ * Get the transform from a schema, or undefined if none exists.
1315
+ */
1316
+ function getTransform(schema) {
1317
+ if (hasTransform(schema)) return schema.transform;
1318
+ }
1319
+ /**
1320
+ * Get the effective equality strategy for a transform.
1321
+ * Default: "reference-equality"
1322
+ */
1323
+ function getEqualityStrategy(schema, strategyIfNotTransformable) {
1324
+ const transform = getTransform(schema);
1325
+ if (!transform) return strategyIfNotTransformable;
1326
+ return transform.isEqual ?? "reference-equality";
1327
+ }
1328
+ /**
1329
+ * Apply decode transform to a CRDT value.
1330
+ * Null/undefined pass through as-is - transform is only called for real values.
1331
+ */
1332
+ function applyDecode(schema, crdtValue) {
1333
+ if (crdtValue === null || crdtValue === void 0) return crdtValue;
1334
+ const transform = getTransform(schema);
1335
+ return transform ? transform.decode(crdtValue) : crdtValue;
1336
+ }
1337
+ /**
1338
+ * Recursively decode JSON values using schema transforms.
1339
+ * Mutates in-place. Used for snapshot initialization where toJSON() skips decode.
1340
+ */
1341
+ function decodeNestedJsonValues(json, schema) {
1342
+ if (json === null || json === void 0 || !schema) return json;
1343
+ switch (schema.type) {
1344
+ case "loro-map":
1345
+ if (!isObject(json)) return json;
1346
+ for (const key of Object.keys(json)) {
1347
+ const fieldSchema = getChildSchema(schema, key);
1348
+ json[key] = decodeNestedJsonValues(json[key], fieldSchema);
1349
+ }
1350
+ return json;
1351
+ case "loro-list":
1352
+ case "loro-movable-list": {
1353
+ if (!Array.isArray(json)) return json;
1354
+ const itemSchema = getChildSchema(schema);
1355
+ for (let i = 0; i < json.length; i++) json[i] = decodeNestedJsonValues(json[i], itemSchema);
1356
+ return json;
1357
+ }
1358
+ case "loro-tree": {
1359
+ if (!Array.isArray(json)) return json;
1360
+ const nodeSchema = getChildSchema(schema);
1361
+ const walk = (nodes) => {
1362
+ for (const node of nodes) if (node != null && typeof node == "object") {
1363
+ if ("data" in node && node.data !== void 0) node.data = decodeNestedJsonValues(node.data, nodeSchema);
1364
+ if ("children" in node && Array.isArray(node.children)) walk(node.children);
1365
+ }
1366
+ };
1367
+ walk(json);
1368
+ return json;
1369
+ }
1370
+ case "loro-text":
1371
+ case "ignore": return json;
1372
+ default: return applyDecode(schema, json);
1373
+ }
1374
+ }
1375
+ /**
1376
+ * Apply encode transform to a domain value.
1377
+ * Null/undefined pass through as-is - transform is only called for real values.
1378
+ */
1379
+ function applyEncode(schema, domainValue) {
1380
+ if (domainValue === null || domainValue === void 0) return domainValue;
1381
+ const transform = getTransform(schema);
1382
+ return transform ? transform.encode(domainValue) : domainValue;
1383
+ }
1384
+ /**
1385
+ * Check if two domain values are equal according to the schema's equality strategy.
1386
+ *
1387
+ * Reference equality is always checked first (performance optimization).
1388
+ * If refs match, returns true (no change).
1389
+ * If refs differ, behavior depends on isEqual setting.
1390
+ */
1391
+ function valuesEqual(schema, oldValue, newValue, strategyIfNotTransformable) {
1392
+ if (oldValue === newValue) return true;
1393
+ const strategy = getEqualityStrategy(schema, strategyIfNotTransformable);
1394
+ if (strategy === "reference-equality") return false;
1395
+ else if (strategy === "encoded-value-equality") return applyEncode(schema, oldValue) === applyEncode(schema, newValue);
1396
+ else if (strategy === "deep-equality") return deepEqual(oldValue, newValue);
1397
+ else return strategy(oldValue, newValue);
1398
+ }
1399
+ function defineCidProperty(target, cid) {
1400
+ if (!isObject(target) || Object.prototype.hasOwnProperty.call(target, "$cid")) return;
1401
+ Object.defineProperty(target, CID_KEY, { value: cid });
1402
+ }
1403
+ /**
1404
+ * Restore the read-only `$cid` contract on a freshly produced state.
1405
+ *
1406
+ * `defineCidProperty` stamps `$cid` as `{ writable: false, enumerable: false,
1407
+ * configurable: false }`. Immer's `useStrictShallowCopy` preserves the descriptor, but it
1408
+ * deliberately rewrites every non-writable data property to `{ writable: true,
1409
+ * configurable: true }` so the draft stays mutable — which would leave `$cid` writable on
1410
+ * every object Immer copied, letting callers reassign a published `$cid`.
1411
+ *
1412
+ * Two things keep this proportional to what Immer actually copied rather than to the size
1413
+ * of the state:
1414
+ *
1415
+ * - `prev` is the state `produce` was called with, and Immer shares everything it did not
1416
+ * copy, so a subtree reference-equal to `prev` cannot have been touched.
1417
+ * - An already-locked `$cid` means this object was not copied this round, so its children
1418
+ * are the same references they were when it was last hardened and are locked too. This
1419
+ * is what makes a reorder cheap: moved items are shared references that land at a new
1420
+ * index, so `prev` no longer lines up with them, but they are still locked.
1421
+ */
1422
+ function hardenCidDescriptors(next, prev, visited) {
1423
+ if (next === prev) return;
1424
+ if (Array.isArray(next)) {
1425
+ if ((visited ?? (visited = /* @__PURE__ */ new Set())).has(next)) return;
1426
+ visited.add(next);
1427
+ const prevArr = Array.isArray(prev) ? prev : void 0;
1428
+ for (let i = 0; i < next.length; i++) hardenCidDescriptors(next[i], prevArr?.[i], visited);
1429
+ return;
1430
+ }
1431
+ if (!isObject(next)) return;
1432
+ const descriptor = Object.getOwnPropertyDescriptor(next, CID_KEY);
1433
+ if (descriptor) {
1434
+ if (!descriptor.configurable) return;
1435
+ if ("value" in descriptor) Object.defineProperty(next, CID_KEY, {
1436
+ value: descriptor.value,
1437
+ writable: false,
1438
+ enumerable: false,
1439
+ configurable: false
1440
+ });
1441
+ }
1442
+ if ((visited ?? (visited = /* @__PURE__ */ new Set())).has(next)) return;
1443
+ visited.add(next);
1444
+ const prevObj = isObject(prev) ? prev : void 0;
1445
+ for (const key of Object.keys(next)) hardenCidDescriptors(next[key], prevObj?.[key], visited);
1446
+ }
1447
+ /**
1448
+ * Check if a value is an object
1449
+ */
1450
+ function isObject(value) {
1451
+ return isPlainObjectValue(value);
1452
+ }
1453
+ const UNSAFE_KEYS = new Set([
1454
+ "__proto__",
1455
+ "constructor",
1456
+ "prototype"
1457
+ ]);
1458
+ /**
1459
+ * Recursively removes undefined values from an object.
1460
+ * This treats undefined values as non-existent fields.
1461
+ * Preserves non-enumerable properties like $cid.
1462
+ * Returns the original object if no undefined values are found.
1463
+ * Protects against prototype pollution by skipping unsafe keys.
1464
+ */
1465
+ function stripUndefined(value) {
1466
+ return stripUndefinedInner(value, 0, void 0);
1467
+ }
1468
+ /**
1469
+ * Depth at which we start recording the recursion path to detect cycles.
1470
+ *
1471
+ * This runs over the whole state on every `setState`, and tracking every node costs more
1472
+ * than the stripping itself. Mirror state is a tree whose depth follows the schema, so a
1473
+ * real state never gets near this; only a cycle recurses without bound. Once the path is
1474
+ * being recorded, any cycle revisits one of its own nodes within a single lap, so starting
1475
+ * late still terminates.
1476
+ */
1477
+ const CYCLE_GUARD_DEPTH = 64;
1478
+ /**
1479
+ * Placeholder for a key that must not reach the rebuilt object: an unsafe key, or one whose
1480
+ * value is `undefined` and is therefore treated as a non-existent field.
1481
+ */
1482
+ const DROPPED = Symbol("dropped");
1483
+ function stripUndefinedInner(value, depth, path) {
1484
+ if (value === void 0) return value;
1485
+ if (Array.isArray(value)) {
1486
+ if (depth >= CYCLE_GUARD_DEPTH) {
1487
+ if ((path ?? (path = /* @__PURE__ */ new Set())).has(value)) return value;
1488
+ path.add(value);
1489
+ }
1490
+ let hasChanges = false;
1491
+ const result = value.map((item) => {
1492
+ const stripped = stripUndefinedInner(item, depth + 1, path);
1493
+ if (stripped !== item) hasChanges = true;
1494
+ return stripped;
1495
+ });
1496
+ path?.delete(value);
1497
+ return hasChanges ? result : value;
1498
+ }
1499
+ if (isObject(value)) {
1500
+ if (depth >= CYCLE_GUARD_DEPTH) {
1501
+ if ((path ?? (path = /* @__PURE__ */ new Set())).has(value)) return value;
1502
+ path.add(value);
1503
+ }
1504
+ const keys = Object.keys(value);
1505
+ const strippedValues = Array.from({ length: keys.length });
1506
+ let changed = false;
1507
+ for (let i = 0; i < keys.length; i++) {
1508
+ const key = keys[i];
1509
+ if (UNSAFE_KEYS.has(key)) {
1510
+ strippedValues[i] = DROPPED;
1511
+ continue;
1512
+ }
1513
+ const val = value[key];
1514
+ if (val === void 0) {
1515
+ strippedValues[i] = DROPPED;
1516
+ changed = true;
1517
+ continue;
1518
+ }
1519
+ const stripped = stripUndefinedInner(val, depth + 1, path);
1520
+ strippedValues[i] = stripped;
1521
+ if (stripped !== val) changed = true;
1522
+ }
1523
+ path?.delete(value);
1524
+ if (!changed) return value;
1525
+ const result = Object.create(null);
1526
+ const allProps = Object.getOwnPropertyNames(value);
1527
+ for (const key of allProps) {
1528
+ if (UNSAFE_KEYS.has(key)) continue;
1529
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
1530
+ if (descriptor && !descriptor.enumerable) Object.defineProperty(result, key, descriptor);
1531
+ }
1532
+ for (let i = 0; i < keys.length; i++) {
1533
+ const val = strippedValues[i];
1534
+ if (val === DROPPED) continue;
1535
+ Object.defineProperty(result, keys[i], {
1536
+ value: val,
1537
+ writable: true,
1538
+ enumerable: true,
1539
+ configurable: true
1540
+ });
1541
+ }
1542
+ return result;
1543
+ }
1544
+ return value;
1545
+ }
1546
+ /**
1547
+ * Performs a deep equality check between two values
1548
+ */
1549
+ function deepEqual(a, b) {
1550
+ if (a === b) return true;
1551
+ if (a === null || b === null || typeof a !== "object" && typeof a !== "function" || typeof b !== "object" && typeof b !== "function") return false;
1552
+ if (Array.isArray(a) && Array.isArray(b)) {
1553
+ if (a.length !== b.length) return false;
1554
+ for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false;
1555
+ return true;
1556
+ }
1557
+ if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
1558
+ if (a instanceof RegExp && b instanceof RegExp) return a.toString() === b.toString();
1559
+ if (!Array.isArray(a) && !Array.isArray(b)) {
1560
+ const keysA = Object.keys(a);
1561
+ const keysB = Object.keys(b);
1562
+ if (keysA.length !== keysB.length) return false;
1563
+ for (const key of keysA) {
1564
+ if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
1565
+ if (!deepEqual(a[key], b[key])) return false;
1566
+ }
1567
+ return true;
1568
+ }
1569
+ return false;
1570
+ }
1571
+ /**
1572
+ * Recursively compare the `$cid` markers of two state trees.
1573
+ *
1574
+ * `deepEqual` only walks enumerable keys, so it cannot see `$cid` (which is stamped as a
1575
+ * non-enumerable descriptor). Used by `Mirror.checkStateConsistency` so that a tampered
1576
+ * or stale `$cid` is reported as a divergence instead of silently sitting in the state.
1577
+ * Only the markers are compared here; value equality is `deepEqual`'s job.
1578
+ */
1579
+ function cidsEqual(a, b, seen) {
1580
+ if (a === b) return true;
1581
+ if (Array.isArray(a) && Array.isArray(b)) {
1582
+ if (a.length !== b.length) return false;
1583
+ if (markSeen(a, b, seen ?? (seen = /* @__PURE__ */ new Map())) === "seen") return true;
1584
+ for (let i = 0; i < a.length; i++) if (!cidsEqual(a[i], b[i], seen)) return false;
1585
+ return true;
1586
+ }
1587
+ if (!isObject(a) || !isObject(b)) return true;
1588
+ if (a["$cid"] !== b["$cid"]) return false;
1589
+ if (markSeen(a, b, seen ?? (seen = /* @__PURE__ */ new Map())) === "seen") return true;
1590
+ for (const key of Object.keys(a)) {
1591
+ if (!Object.prototype.hasOwnProperty.call(b, key)) continue;
1592
+ if (!cidsEqual(a[key], b[key], seen)) return false;
1593
+ }
1594
+ return true;
1595
+ }
1596
+ function markSeen(a, b, seen) {
1597
+ let partners = seen.get(a);
1598
+ if (!partners) {
1599
+ partners = /* @__PURE__ */ new Set();
1600
+ seen.set(a, partners);
1601
+ }
1602
+ if (partners.has(b)) return "seen";
1603
+ partners.add(b);
1604
+ return "new";
1605
+ }
1606
+ function containerIdToContainerType(containerId) {
1607
+ const parts = containerId.split(":");
1608
+ return parts[parts.length - 1];
1609
+ }
1610
+ function getRootContainerByType(doc, key, type) {
1611
+ if (type === "Text") return doc.getText(key);
1612
+ else if (type === "List") return doc.getList(key);
1613
+ else if (type === "MovableList") return doc.getMovableList(key);
1614
+ else if (type === "Map") return doc.getMap(key);
1615
+ else if (type === "Tree") return doc.getTree(key);
1616
+ else throw new Error();
1617
+ }
1618
+ function insertChildToMap(containerId, key, value, inferOptions) {
1619
+ const ct = tryInferContainerType(value, inferOptions);
1620
+ if (ct) return {
1621
+ container: containerId,
1622
+ key,
1623
+ value,
1624
+ kind: "insert-container",
1625
+ childContainerType: ct
1626
+ };
1627
+ return {
1628
+ container: containerId,
1629
+ key,
1630
+ value,
1631
+ kind: "insert"
1632
+ };
1633
+ }
1634
+ function tryUpdateToContainer(change, toUpdate, schema, inferOptions) {
1635
+ if (!toUpdate) return change;
1636
+ if (change.kind !== "insert" && change.kind !== "set") return change;
1637
+ const effectiveInferOptions = applySchemaToInferOptions(schema, inferOptions);
1638
+ const containerType = schema ? schemaToContainerType(schema) ?? tryInferContainerType(change.value, effectiveInferOptions) : tryInferContainerType(change.value, effectiveInferOptions);
1639
+ if (containerType == null || schema && hasTransform(schema)) {
1640
+ const encodedValue = applyEncode(schema, change.value);
1641
+ return encodedValue !== change.value ? {
1642
+ ...change,
1643
+ value: encodedValue
1644
+ } : change;
1645
+ }
1646
+ if (change.kind === "insert") return {
1647
+ container: change.container,
1648
+ key: change.key,
1649
+ value: change.value,
1650
+ kind: "insert-container",
1651
+ childContainerType: containerType
1652
+ };
1653
+ if (change.kind === "set") return {
1654
+ container: change.container,
1655
+ key: change.key,
1656
+ value: change.value,
1657
+ kind: "set-container",
1658
+ childContainerType: containerType
1659
+ };
1660
+ return change;
1661
+ }
1662
+ function schemaToContainerType(schema) {
1663
+ const containerType = schema.getContainerType();
1664
+ return containerType === null ? void 0 : containerType;
1665
+ }
1666
+ function tryInferContainerType(value, defaults) {
1667
+ return inferContainerTypeFromValue$1(value, defaults);
1668
+ }
1669
+ function applySchemaToInferOptions(schema, base) {
1670
+ if (!schema || schema.type !== "any") return base;
1671
+ const next = { ...base };
1672
+ next.defaultLoroText = schema.options.defaultLoroText ?? false;
1673
+ if (schema.options.defaultMovableList !== void 0) next.defaultMovableList = schema.options.defaultMovableList;
1674
+ return next;
1675
+ }
1676
+ function isValueOfContainerType(containerType, value) {
1677
+ return matchesContainerType(containerType, value);
1678
+ }
1679
+ function inferContainerTypeFromValue(value, defaults) {
1680
+ return inferSchemaContainerTypeFromValue(value, defaults);
1681
+ }
1682
+ function isObjectLike(value) {
1683
+ return typeof value === "object";
1684
+ }
1685
+ function isArrayLike(value) {
1686
+ return Array.isArray(value);
1687
+ }
1688
+ function isStateAndSchemaOfType(values, stateGuard, schemaGuard) {
1689
+ return stateGuard(values.oldState) && stateGuard(values.newState) && (!values.schema || schemaGuard(values.schema));
1690
+ }
1691
+ function isTreeID(id) {
1692
+ if (!(typeof id === "string")) return false;
1693
+ return !!id.match(/[0-9]+@[0-9]+/);
1694
+ }
1695
+ /**
1696
+ * Stringify a value safely, handling non-JSON-serializable types.
1697
+ * Handles BigInt, Date, RegExp, functions, and custom objects.
1698
+ */
1699
+ function safeStringify(value, indent = 2) {
1700
+ const seen = /* @__PURE__ */ new WeakSet();
1701
+ function replacer(val) {
1702
+ if (val === null || val === void 0) return val;
1703
+ if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") return val;
1704
+ if (typeof val === "bigint") return `[BigInt: ${val.toString()}]`;
1705
+ if (typeof val === "function") return `[Function: ${val.name || "anonymous"}]`;
1706
+ if (typeof val === "symbol") return `[Symbol: ${val.description || ""}]`;
1707
+ if (typeof val === "object") {
1708
+ if (seen.has(val)) return "[Circular]";
1709
+ seen.add(val);
1710
+ if (val instanceof Date) return `[Date: ${val.toISOString()}]`;
1711
+ if (val instanceof RegExp) return `[RegExp: ${val.toString()}]`;
1712
+ if (val instanceof Error) return `[Error: ${val.message}]`;
1713
+ if (Array.isArray(val)) return val.map(replacer);
1714
+ const result = {};
1715
+ for (const key of Object.keys(val)) result[key] = replacer(val[key]);
1716
+ return result;
1717
+ }
1718
+ return Object.prototype.toString.call(val);
1719
+ }
1720
+ return JSON.stringify(replacer(value), null, indent);
1721
+ }
1722
+ //#endregion
1723
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/schema/validators.js
1724
+ const schemaValidationCache = /* @__PURE__ */ new WeakMap();
1725
+ function isCacheableValue(value) {
1726
+ return typeof value === "object" && value !== null;
1727
+ }
1728
+ function isSchemaValidated(schema, value) {
1729
+ if (!isCacheableValue(value)) return false;
1730
+ return schemaValidationCache.get(value)?.has(schema) ?? false;
1731
+ }
1732
+ function markSchemaValidated(schema, value) {
1733
+ if (!isCacheableValue(value)) return;
1734
+ let cache = schemaValidationCache.get(value);
1735
+ if (!cache) {
1736
+ cache = /* @__PURE__ */ new WeakSet();
1737
+ schemaValidationCache.set(value, cache);
1738
+ }
1739
+ cache.add(schema);
1740
+ }
1741
+ /**
1742
+ * Type guard for LoroMapSchema
1743
+ */
1744
+ function isLoroMapSchema(schema) {
1745
+ return !!schema && schema.type === "loro-map";
1746
+ }
1747
+ /**
1748
+ * Type guard for LoroListSchema
1749
+ */
1750
+ function isLoroListSchema(schema) {
1751
+ return !!schema && schema.type === "loro-list";
1752
+ }
1753
+ function isListLikeSchema(schema) {
1754
+ return isLoroListSchema(schema) || isLoroMovableListSchema(schema);
1755
+ }
1756
+ function isLoroMovableListSchema(schema) {
1757
+ return !!schema && schema.type === "loro-movable-list";
1758
+ }
1759
+ /**
1760
+ * Type guard for RootSchemaType
1761
+ */
1762
+ function isRootSchemaType(schema) {
1763
+ return !!schema && schema.type === "schema";
1764
+ }
1765
+ /**
1766
+ * Whether a schema subtree contains any `Ignore` field. Recursive schemas are
1767
+ * tolerated (each schema object is visited once).
1768
+ */
1769
+ function schemaContainsIgnoreField(schema) {
1770
+ const visited = /* @__PURE__ */ new Set();
1771
+ const walk = (s) => {
1772
+ if (!s || visited.has(s)) return false;
1773
+ visited.add(s);
1774
+ if (s.type === "ignore") return true;
1775
+ switch (s.type) {
1776
+ case "schema":
1777
+ case "loro-map": {
1778
+ const record = s;
1779
+ return Object.values(record.definition).some(walk) || walk(record.catchallType);
1780
+ }
1781
+ case "loro-list":
1782
+ case "loro-movable-list": return walk(s.itemSchema);
1783
+ case "loro-tree": return walk(s.nodeSchema);
1784
+ default: return false;
1785
+ }
1786
+ };
1787
+ return walk(schema);
1788
+ }
1789
+ /**
1790
+ * Type guard for LoroTreeSchema
1791
+ */
1792
+ function isLoroTreeSchema(schema) {
1793
+ return !!schema && schema.type === "loro-tree";
1794
+ }
1795
+ /**
1796
+ * Check if a schema is for a Loro container
1797
+ */
1798
+ function isContainerSchema(schema) {
1799
+ return !!schema && (schema.type === "loro-map" || schema.type === "loro-list" || schema.type === "loro-text" || schema.type === "loro-movable-list" || schema.type === "loro-tree");
1800
+ }
1801
+ /**
1802
+ * Validate a value against a schema
1803
+ *
1804
+ * When `options.ignoreUnknownProperties` is true, the root schema check does
1805
+ * not reject properties missing from the schema definition — typically
1806
+ * written by peers on a newer schema version. (Nested map schemas never
1807
+ * reject undeclared properties.)
1808
+ */
1809
+ function validateSchema(schema, value, options) {
1810
+ const errors = [];
1811
+ const actualType = schema.type;
1812
+ if (schema.options.required && (value === void 0 || value === null)) {
1813
+ errors.push("Value is required");
1814
+ return {
1815
+ valid: false,
1816
+ errors
1817
+ };
1818
+ }
1819
+ if (value === void 0 || value === null) return { valid: true };
1820
+ const useCache = !options?.ignoreUnknownProperties;
1821
+ if (useCache && isSchemaValidated(schema, value)) return { valid: true };
1822
+ switch (actualType) {
1823
+ case "any":
1824
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean" && value !== null && value !== void 0 && !Array.isArray(value) && !isObject(value)) errors.push("Value must be JSON-like");
1825
+ break;
1826
+ case "string":
1827
+ case "number":
1828
+ case "boolean":
1829
+ validateTransformablePrimitive(schema, value, actualType, errors);
1830
+ break;
1831
+ case "ignore": break;
1832
+ case "loro-text":
1833
+ if (typeof value !== "string") errors.push("Content must be a string");
1834
+ break;
1835
+ case "loro-map":
1836
+ if (!isObject(value)) errors.push("Value must be an object");
1837
+ else if (isLoroMapSchema(schema)) {
1838
+ for (const key in schema.definition) if (Object.prototype.hasOwnProperty.call(schema.definition, key)) {
1839
+ const propSchema = schema.definition[key];
1840
+ const propValue = value[key];
1841
+ const result = validateSchema(propSchema, propValue);
1842
+ if (!result.valid && result.errors) {
1843
+ const prefixedErrors = result.errors.map((err) => `${key}: ${err}`);
1844
+ errors.push(...prefixedErrors);
1845
+ }
1846
+ }
1847
+ }
1848
+ break;
1849
+ case "loro-movable-list":
1850
+ case "loro-list":
1851
+ if (!Array.isArray(value)) errors.push("Value must be an array");
1852
+ else if (isLoroListSchema(schema) || isLoroMovableListSchema(schema)) {
1853
+ const itemSchema = schema.itemSchema;
1854
+ value.forEach((item, index) => {
1855
+ const result = validateSchema(itemSchema, item);
1856
+ if (!result.valid && result.errors) {
1857
+ const prefixedErrors = result.errors.map((err) => `Item ${index}: ${err}`);
1858
+ errors.push(...prefixedErrors);
1859
+ }
1860
+ });
1861
+ }
1862
+ break;
1863
+ case "loro-tree": {
1864
+ if (!Array.isArray(value)) {
1865
+ errors.push("Value must be an array of tree nodes");
1866
+ break;
1867
+ }
1868
+ if (!isLoroTreeSchema(schema)) {
1869
+ errors.push("Invalid tree schema");
1870
+ break;
1871
+ }
1872
+ const validateNode = (node, path) => {
1873
+ if (!isObject(node)) {
1874
+ errors.push(`${path}: Node must be an object`);
1875
+ return;
1876
+ }
1877
+ const n = node;
1878
+ if (n.id != null && typeof n.id !== "string") errors.push(`${path}: id must be a string if provided`);
1879
+ const dataResult = validateSchema(schema.nodeSchema, n.data);
1880
+ if (!dataResult.valid && dataResult.errors) errors.push(...dataResult.errors.map((e) => `${path}.data: ${e}`));
1881
+ if (!Array.isArray(n.children)) errors.push(`${path}: children must be an array`);
1882
+ else n.children.forEach((child, idx) => {
1883
+ validateNode(child, `${path}.children[${idx}]`);
1884
+ });
1885
+ };
1886
+ value.forEach((node, i) => {
1887
+ validateNode(node, `node[${i}]`);
1888
+ });
1889
+ break;
1890
+ }
1891
+ case "schema":
1892
+ if (!isObject(value)) errors.push("Value must be an object");
1893
+ else if (isRootSchemaType(schema)) if (!isObject(value)) errors.push("Value must be an object");
1894
+ else {
1895
+ for (const key in schema.definition) if (Object.prototype.hasOwnProperty.call(schema.definition, key)) {
1896
+ const propSchema = schema.definition[key];
1897
+ const propValue = value[key];
1898
+ const result = validateSchema(propSchema, propValue);
1899
+ if (!result.valid && result.errors) {
1900
+ const prefixedErrors = result.errors.map((err) => `${key}: ${err}`);
1901
+ errors.push(...prefixedErrors);
1902
+ }
1903
+ }
1904
+ for (const key in value) if (!Object.prototype.hasOwnProperty.call(schema.definition, key)) {
1905
+ if (options?.ignoreUnknownProperties) continue;
1906
+ errors.push(`Unknown property: ${key}`);
1907
+ }
1908
+ }
1909
+ else errors.push(`Should be a schema, but got ${actualType}`);
1910
+ break;
1911
+ default: errors.push(`Unknown schema type: ${actualType}`);
1912
+ }
1913
+ if (schema.options.validate && typeof schema.options.validate === "function") try {
1914
+ const customValidation = schema.options.validate(value);
1915
+ if (customValidation !== true) {
1916
+ const errorMessage = typeof customValidation === "string" ? customValidation : "Value failed custom validation";
1917
+ errors.push(errorMessage);
1918
+ }
1919
+ } catch (error) {
1920
+ errors.push(`Validation error: ${String(error)}`);
1921
+ }
1922
+ if (errors.length === 0) {
1923
+ if (useCache) markSchemaValidated(schema, value);
1924
+ return { valid: true };
1925
+ }
1926
+ return {
1927
+ valid: false,
1928
+ errors
1929
+ };
1930
+ }
1931
+ function validateTransformablePrimitive(schema, value, expectedType, errors) {
1932
+ const transform = getTransform(schema);
1933
+ if (transform) {
1934
+ if (transform.validate) try {
1935
+ const result = transform.validate(value);
1936
+ if (result !== true) errors.push(typeof result === "string" ? result : "Transform validation failed");
1937
+ } catch (error) {
1938
+ errors.push(`Transform validation error: ${String(error)}`);
1939
+ }
1940
+ if (transform.validateEncodedType) try {
1941
+ const encoded = applyEncode(schema, value);
1942
+ if (typeof encoded !== expectedType) errors.push(`Transform encode must return a ${expectedType}, got ${typeof encoded}`);
1943
+ } catch (error) {
1944
+ errors.push(`Transform encode validation error: ${String(error)}`);
1945
+ }
1946
+ } else if (typeof value !== expectedType) errors.push(`Value must be a ${expectedType}`);
1947
+ }
1948
+ /**
1949
+ * Get default value for a schema
1950
+ * Based on the schema type, it might return a plain value or a wrapped value
1951
+ */
1952
+ function getDefaultValue(schema) {
1953
+ if ("defaultValue" in schema.options) return schema.options.defaultValue;
1954
+ switch (schema.type) {
1955
+ case "any": return;
1956
+ case "string":
1957
+ if (schema.options.required === false) return;
1958
+ if (getTransform(schema)) return;
1959
+ return "";
1960
+ case "number":
1961
+ if (schema.options.required === false) return;
1962
+ if (getTransform(schema)) return;
1963
+ return 0;
1964
+ case "boolean":
1965
+ if (schema.options.required === false) return;
1966
+ if (getTransform(schema)) return;
1967
+ return false;
1968
+ case "loro-text": {
1969
+ const value = schema.options.required ? "" : void 0;
1970
+ if (value === void 0) return void 0;
1971
+ return value;
1972
+ }
1973
+ case "loro-map":
1974
+ if (isLoroMapSchema(schema)) {
1975
+ const result = {};
1976
+ for (const key in schema.definition) if (Object.prototype.hasOwnProperty.call(schema.definition, key)) {
1977
+ const value = getDefaultValue(schema.definition[key]);
1978
+ if (value !== void 0) result[key] = value;
1979
+ }
1980
+ return result;
1981
+ }
1982
+ return {};
1983
+ case "loro-list": return [];
1984
+ case "loro-tree": {
1985
+ const value = schema.options.required ? [] : void 0;
1986
+ if (value === void 0) return void 0;
1987
+ return value;
1988
+ }
1989
+ case "schema":
1990
+ if (isRootSchemaType(schema)) {
1991
+ const result = {};
1992
+ for (const key in schema.definition) if (Object.prototype.hasOwnProperty.call(schema.definition, key)) {
1993
+ const value = getDefaultValue(schema.definition[key]);
1994
+ if (value !== void 0) result[key] = value;
1995
+ }
1996
+ return result;
1997
+ }
1998
+ return {};
1999
+ default: return;
2000
+ }
2001
+ }
2002
+ //#endregion
2003
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/schema/index.js
2004
+ /**
2005
+ * Create a schema definition
2006
+ */
2007
+ function schema(definition, options) {
2008
+ return {
2009
+ type: "schema",
2010
+ definition,
2011
+ options: options || {},
2012
+ getContainerType() {
2013
+ return "Map";
2014
+ }
2015
+ };
2016
+ }
2017
+ /**
2018
+ * Define a string field
2019
+ */
2020
+ schema.String = (function(options) {
2021
+ const baseSchema = {
2022
+ type: "string",
2023
+ options: options || {},
2024
+ getContainerType: () => {
2025
+ return null;
2026
+ }
2027
+ };
2028
+ return {
2029
+ ...baseSchema,
2030
+ transform: (def) => ({
2031
+ ...baseSchema,
2032
+ transform: def
2033
+ })
2034
+ };
2035
+ });
2036
+ /**
2037
+ * Define an any field (runtime-inferred by Mirror)
2038
+ */
2039
+ schema.Any = function(options) {
2040
+ return {
2041
+ type: "any",
2042
+ options: options || {},
2043
+ getContainerType: () => {
2044
+ return null;
2045
+ }
2046
+ };
2047
+ };
2048
+ /**
2049
+ * Define a number field
2050
+ */
2051
+ schema.Number = function(options) {
2052
+ const baseSchema = {
2053
+ type: "number",
2054
+ options: options || {},
2055
+ getContainerType: () => {
2056
+ return null;
2057
+ }
2058
+ };
2059
+ return {
2060
+ ...baseSchema,
2061
+ transform: (def) => ({
2062
+ ...baseSchema,
2063
+ transform: def
2064
+ })
2065
+ };
2066
+ };
2067
+ /**
2068
+ * Define a boolean field
2069
+ */
2070
+ schema.Boolean = function(options) {
2071
+ const baseSchema = {
2072
+ type: "boolean",
2073
+ options: options || {},
2074
+ getContainerType: () => {
2075
+ return null;
2076
+ }
2077
+ };
2078
+ return {
2079
+ ...baseSchema,
2080
+ transform: (def) => ({
2081
+ ...baseSchema,
2082
+ transform: def
2083
+ })
2084
+ };
2085
+ };
2086
+ /**
2087
+ * Define a field to be ignored (not synced with Loro)
2088
+ */
2089
+ schema.Ignore = function(options) {
2090
+ return {
2091
+ type: "ignore",
2092
+ options: options || {},
2093
+ getContainerType: () => {
2094
+ return null;
2095
+ }
2096
+ };
2097
+ };
2098
+ /**
2099
+ * Define a Loro map
2100
+ */
2101
+ schema.LoroMap = function(definition, options) {
2102
+ const baseSchema = {
2103
+ type: "loro-map",
2104
+ definition,
2105
+ options: options || {},
2106
+ getContainerType: () => {
2107
+ return "Map";
2108
+ }
2109
+ };
2110
+ const schemaWithCatchall = {
2111
+ ...baseSchema,
2112
+ catchall: (catchallSchema) => {
2113
+ return {
2114
+ ...baseSchema,
2115
+ catchallType: catchallSchema,
2116
+ catchall: (newCatchallSchema) => {
2117
+ return {
2118
+ ...baseSchema,
2119
+ catchallType: newCatchallSchema,
2120
+ catchall: schemaWithCatchall.catchall
2121
+ };
2122
+ }
2123
+ };
2124
+ }
2125
+ };
2126
+ return schemaWithCatchall;
2127
+ };
2128
+ /**
2129
+ * Create a dynamic record schema (like zod's z.record)
2130
+ */
2131
+ schema.LoroMapRecord = function(valueSchema, options) {
2132
+ return {
2133
+ type: "loro-map",
2134
+ definition: {},
2135
+ catchallType: valueSchema,
2136
+ options: options || {},
2137
+ getContainerType: () => {
2138
+ return "Map";
2139
+ },
2140
+ catchall: (newCatchallSchema) => {
2141
+ return schema.LoroMapRecord(newCatchallSchema, options);
2142
+ }
2143
+ };
2144
+ };
2145
+ /**
2146
+ * Define a Loro list
2147
+ */
2148
+ schema.LoroList = function(itemSchema, idSelector, options) {
2149
+ return {
2150
+ type: "loro-list",
2151
+ itemSchema,
2152
+ idSelector,
2153
+ options: options || {},
2154
+ getContainerType: () => {
2155
+ return "List";
2156
+ }
2157
+ };
2158
+ };
2159
+ schema.LoroMovableList = function(itemSchema, idSelector, options) {
2160
+ return {
2161
+ type: "loro-movable-list",
2162
+ itemSchema,
2163
+ idSelector,
2164
+ options: options || {},
2165
+ getContainerType: () => {
2166
+ return "MovableList";
2167
+ }
2168
+ };
2169
+ };
2170
+ /**
2171
+ * Define a Loro text field
2172
+ */
2173
+ schema.LoroText = function(options) {
2174
+ return {
2175
+ type: "loro-text",
2176
+ options: options || {},
2177
+ getContainerType: () => {
2178
+ return "Text";
2179
+ }
2180
+ };
2181
+ };
2182
+ /**
2183
+ * Define a Loro tree
2184
+ *
2185
+ * Each tree node has a `data` map described by `nodeSchema`.
2186
+ */
2187
+ schema.LoroTree = function(nodeSchema, options) {
2188
+ return {
2189
+ type: "loro-tree",
2190
+ nodeSchema,
2191
+ options: options || {},
2192
+ getContainerType() {
2193
+ return "Tree";
2194
+ }
2195
+ };
2196
+ };
2197
+ //#endregion
2198
+ //#region ../../node_modules/.pnpm/immer@10.2.0/node_modules/immer/dist/immer.mjs
2199
+ var NOTHING = Symbol.for("immer-nothing");
2200
+ var DRAFTABLE = Symbol.for("immer-draftable");
2201
+ var DRAFT_STATE = Symbol.for("immer-state");
2202
+ var errors = [
2203
+ function(plugin) {
2204
+ return `The plugin for '${plugin}' has not been loaded into Immer. To enable the plugin, import and call \`enable${plugin}()\` when initializing your application.`;
2205
+ },
2206
+ function(thing) {
2207
+ return `produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '${thing}'`;
2208
+ },
2209
+ "This object has been frozen and should not be mutated",
2210
+ function(data) {
2211
+ return "Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? " + data;
2212
+ },
2213
+ "An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.",
2214
+ "Immer forbids circular references",
2215
+ "The first or second argument to `produce` must be a function",
2216
+ "The third argument to `produce` must be a function or undefined",
2217
+ "First argument to `createDraft` must be a plain object, an array, or an immerable object",
2218
+ "First argument to `finishDraft` must be a draft returned by `createDraft`",
2219
+ function(thing) {
2220
+ return `'current' expects a draft, got: ${thing}`;
2221
+ },
2222
+ "Object.defineProperty() cannot be used on an Immer draft",
2223
+ "Object.setPrototypeOf() cannot be used on an Immer draft",
2224
+ "Immer only supports deleting array indices",
2225
+ "Immer only supports setting array indices and the 'length' property",
2226
+ function(thing) {
2227
+ return `'original' expects a draft, got: ${thing}`;
2228
+ }
2229
+ ];
2230
+ function die(error, ...args) {
2231
+ {
2232
+ const e = errors[error];
2233
+ const msg = typeof e === "function" ? e.apply(null, args) : e;
2234
+ throw new Error(`[Immer] ${msg}`);
2235
+ }
2236
+ throw new Error(`[Immer] minified error nr: ${error}. Full error at: https://bit.ly/3cXEKWf`);
2237
+ }
2238
+ var getPrototypeOf = Object.getPrototypeOf;
2239
+ function isDraft(value) {
2240
+ return !!value && !!value[DRAFT_STATE];
2241
+ }
2242
+ function isDraftable(value) {
2243
+ if (!value) return false;
2244
+ return isPlainObject(value) || Array.isArray(value) || !!value[DRAFTABLE] || !!value.constructor?.[DRAFTABLE] || isMap(value) || isSet(value);
2245
+ }
2246
+ var objectCtorString = Object.prototype.constructor.toString();
2247
+ var cachedCtorStrings = /* @__PURE__ */ new WeakMap();
2248
+ function isPlainObject(value) {
2249
+ if (!value || typeof value !== "object") return false;
2250
+ const proto = Object.getPrototypeOf(value);
2251
+ if (proto === null || proto === Object.prototype) return true;
2252
+ const Ctor = Object.hasOwnProperty.call(proto, "constructor") && proto.constructor;
2253
+ if (Ctor === Object) return true;
2254
+ if (typeof Ctor !== "function") return false;
2255
+ let ctorString = cachedCtorStrings.get(Ctor);
2256
+ if (ctorString === void 0) {
2257
+ ctorString = Function.toString.call(Ctor);
2258
+ cachedCtorStrings.set(Ctor, ctorString);
2259
+ }
2260
+ return ctorString === objectCtorString;
2261
+ }
2262
+ function each(obj, iter, strict = true) {
2263
+ if (getArchtype(obj) === 0) (strict ? Reflect.ownKeys(obj) : Object.keys(obj)).forEach((key) => {
2264
+ iter(key, obj[key], obj);
2265
+ });
2266
+ else obj.forEach((entry, index) => iter(index, entry, obj));
2267
+ }
2268
+ function getArchtype(thing) {
2269
+ const state = thing[DRAFT_STATE];
2270
+ return state ? state.type_ : Array.isArray(thing) ? 1 : isMap(thing) ? 2 : isSet(thing) ? 3 : 0;
2271
+ }
2272
+ function has(thing, prop) {
2273
+ return getArchtype(thing) === 2 ? thing.has(prop) : Object.prototype.hasOwnProperty.call(thing, prop);
2274
+ }
2275
+ function set(thing, propOrOldValue, value) {
2276
+ const t = getArchtype(thing);
2277
+ if (t === 2) thing.set(propOrOldValue, value);
2278
+ else if (t === 3) thing.add(value);
2279
+ else thing[propOrOldValue] = value;
2280
+ }
2281
+ function is(x, y) {
2282
+ if (x === y) return x !== 0 || 1 / x === 1 / y;
2283
+ else return x !== x && y !== y;
2284
+ }
2285
+ function isMap(target) {
2286
+ return target instanceof Map;
2287
+ }
2288
+ function isSet(target) {
2289
+ return target instanceof Set;
2290
+ }
2291
+ function latest(state) {
2292
+ return state.copy_ || state.base_;
2293
+ }
2294
+ function shallowCopy(base, strict) {
2295
+ if (isMap(base)) return new Map(base);
2296
+ if (isSet(base)) return new Set(base);
2297
+ if (Array.isArray(base)) return Array.prototype.slice.call(base);
2298
+ const isPlain = isPlainObject(base);
2299
+ if (strict === true || strict === "class_only" && !isPlain) {
2300
+ const descriptors = Object.getOwnPropertyDescriptors(base);
2301
+ delete descriptors[DRAFT_STATE];
2302
+ let keys = Reflect.ownKeys(descriptors);
2303
+ for (let i = 0; i < keys.length; i++) {
2304
+ const key = keys[i];
2305
+ const desc = descriptors[key];
2306
+ if (desc.writable === false) {
2307
+ desc.writable = true;
2308
+ desc.configurable = true;
2309
+ }
2310
+ if (desc.get || desc.set) descriptors[key] = {
2311
+ configurable: true,
2312
+ writable: true,
2313
+ enumerable: desc.enumerable,
2314
+ value: base[key]
2315
+ };
2316
+ }
2317
+ return Object.create(getPrototypeOf(base), descriptors);
2318
+ } else {
2319
+ const proto = getPrototypeOf(base);
2320
+ if (proto !== null && isPlain) return { ...base };
2321
+ return Object.assign(Object.create(proto), base);
2322
+ }
2323
+ }
2324
+ function freeze(obj, deep = false) {
2325
+ if (isFrozen(obj) || isDraft(obj) || !isDraftable(obj)) return obj;
2326
+ if (getArchtype(obj) > 1) Object.defineProperties(obj, {
2327
+ set: dontMutateMethodOverride,
2328
+ add: dontMutateMethodOverride,
2329
+ clear: dontMutateMethodOverride,
2330
+ delete: dontMutateMethodOverride
2331
+ });
2332
+ Object.freeze(obj);
2333
+ if (deep) Object.values(obj).forEach((value) => freeze(value, true));
2334
+ return obj;
2335
+ }
2336
+ function dontMutateFrozenCollections() {
2337
+ die(2);
2338
+ }
2339
+ var dontMutateMethodOverride = { value: dontMutateFrozenCollections };
2340
+ function isFrozen(obj) {
2341
+ if (obj === null || typeof obj !== "object") return true;
2342
+ return Object.isFrozen(obj);
2343
+ }
2344
+ var plugins = {};
2345
+ function getPlugin(pluginKey) {
2346
+ const plugin = plugins[pluginKey];
2347
+ if (!plugin) die(0, pluginKey);
2348
+ return plugin;
2349
+ }
2350
+ var currentScope;
2351
+ function getCurrentScope() {
2352
+ return currentScope;
2353
+ }
2354
+ function createScope(parent_, immer_) {
2355
+ return {
2356
+ drafts_: [],
2357
+ parent_,
2358
+ immer_,
2359
+ canAutoFreeze_: true,
2360
+ unfinalizedDrafts_: 0
2361
+ };
2362
+ }
2363
+ function usePatchesInScope(scope, patchListener) {
2364
+ if (patchListener) {
2365
+ getPlugin("Patches");
2366
+ scope.patches_ = [];
2367
+ scope.inversePatches_ = [];
2368
+ scope.patchListener_ = patchListener;
2369
+ }
2370
+ }
2371
+ function revokeScope(scope) {
2372
+ leaveScope(scope);
2373
+ scope.drafts_.forEach(revokeDraft);
2374
+ scope.drafts_ = null;
2375
+ }
2376
+ function leaveScope(scope) {
2377
+ if (scope === currentScope) currentScope = scope.parent_;
2378
+ }
2379
+ function enterScope(immer2) {
2380
+ return currentScope = createScope(currentScope, immer2);
2381
+ }
2382
+ function revokeDraft(draft) {
2383
+ const state = draft[DRAFT_STATE];
2384
+ if (state.type_ === 0 || state.type_ === 1) state.revoke_();
2385
+ else state.revoked_ = true;
2386
+ }
2387
+ function processResult(result, scope) {
2388
+ scope.unfinalizedDrafts_ = scope.drafts_.length;
2389
+ const baseDraft = scope.drafts_[0];
2390
+ if (result !== void 0 && result !== baseDraft) {
2391
+ if (baseDraft[DRAFT_STATE].modified_) {
2392
+ revokeScope(scope);
2393
+ die(4);
2394
+ }
2395
+ if (isDraftable(result)) {
2396
+ result = finalize(scope, result);
2397
+ if (!scope.parent_) maybeFreeze(scope, result);
2398
+ }
2399
+ if (scope.patches_) getPlugin("Patches").generateReplacementPatches_(baseDraft[DRAFT_STATE].base_, result, scope.patches_, scope.inversePatches_);
2400
+ } else result = finalize(scope, baseDraft, []);
2401
+ revokeScope(scope);
2402
+ if (scope.patches_) scope.patchListener_(scope.patches_, scope.inversePatches_);
2403
+ return result !== NOTHING ? result : void 0;
2404
+ }
2405
+ function finalize(rootScope, value, path) {
2406
+ if (isFrozen(value)) return value;
2407
+ const useStrictIteration = rootScope.immer_.shouldUseStrictIteration();
2408
+ const state = value[DRAFT_STATE];
2409
+ if (!state) {
2410
+ each(value, (key, childValue) => finalizeProperty(rootScope, state, value, key, childValue, path), useStrictIteration);
2411
+ return value;
2412
+ }
2413
+ if (state.scope_ !== rootScope) return value;
2414
+ if (!state.modified_) {
2415
+ maybeFreeze(rootScope, state.base_, true);
2416
+ return state.base_;
2417
+ }
2418
+ if (!state.finalized_) {
2419
+ state.finalized_ = true;
2420
+ state.scope_.unfinalizedDrafts_--;
2421
+ const result = state.copy_;
2422
+ let resultEach = result;
2423
+ let isSet2 = false;
2424
+ if (state.type_ === 3) {
2425
+ resultEach = new Set(result);
2426
+ result.clear();
2427
+ isSet2 = true;
2428
+ }
2429
+ each(resultEach, (key, childValue) => finalizeProperty(rootScope, state, result, key, childValue, path, isSet2), useStrictIteration);
2430
+ maybeFreeze(rootScope, result, false);
2431
+ if (path && rootScope.patches_) getPlugin("Patches").generatePatches_(state, path, rootScope.patches_, rootScope.inversePatches_);
2432
+ }
2433
+ return state.copy_;
2434
+ }
2435
+ function finalizeProperty(rootScope, parentState, targetObject, prop, childValue, rootPath, targetIsSet) {
2436
+ if (childValue == null) return;
2437
+ if (typeof childValue !== "object" && !targetIsSet) return;
2438
+ const childIsFrozen = isFrozen(childValue);
2439
+ if (childIsFrozen && !targetIsSet) return;
2440
+ if (childValue === targetObject) die(5);
2441
+ if (isDraft(childValue)) {
2442
+ const res = finalize(rootScope, childValue, rootPath && parentState && parentState.type_ !== 3 && !has(parentState.assigned_, prop) ? rootPath.concat(prop) : void 0);
2443
+ set(targetObject, prop, res);
2444
+ if (isDraft(res)) rootScope.canAutoFreeze_ = false;
2445
+ else return;
2446
+ } else if (targetIsSet) targetObject.add(childValue);
2447
+ if (isDraftable(childValue) && !childIsFrozen) {
2448
+ if (!rootScope.immer_.autoFreeze_ && rootScope.unfinalizedDrafts_ < 1) return;
2449
+ if (parentState && parentState.base_ && parentState.base_[prop] === childValue && childIsFrozen) return;
2450
+ finalize(rootScope, childValue);
2451
+ if ((!parentState || !parentState.scope_.parent_) && typeof prop !== "symbol" && (isMap(targetObject) ? targetObject.has(prop) : Object.prototype.propertyIsEnumerable.call(targetObject, prop))) maybeFreeze(rootScope, childValue);
2452
+ }
2453
+ }
2454
+ function maybeFreeze(scope, value, deep = false) {
2455
+ if (!scope.parent_ && scope.immer_.autoFreeze_ && scope.canAutoFreeze_) freeze(value, deep);
2456
+ }
2457
+ function createProxyProxy(base, parent) {
2458
+ const isArray = Array.isArray(base);
2459
+ const state = {
2460
+ type_: isArray ? 1 : 0,
2461
+ scope_: parent ? parent.scope_ : getCurrentScope(),
2462
+ modified_: false,
2463
+ finalized_: false,
2464
+ assigned_: {},
2465
+ parent_: parent,
2466
+ base_: base,
2467
+ draft_: null,
2468
+ copy_: null,
2469
+ revoke_: null,
2470
+ isManual_: false
2471
+ };
2472
+ let target = state;
2473
+ let traps = objectTraps;
2474
+ if (isArray) {
2475
+ target = [state];
2476
+ traps = arrayTraps;
2477
+ }
2478
+ const { revoke, proxy } = Proxy.revocable(target, traps);
2479
+ state.draft_ = proxy;
2480
+ state.revoke_ = revoke;
2481
+ return proxy;
2482
+ }
2483
+ var objectTraps = {
2484
+ get(state, prop) {
2485
+ if (prop === DRAFT_STATE) return state;
2486
+ const source = latest(state);
2487
+ if (!has(source, prop)) return readPropFromProto(state, source, prop);
2488
+ const value = source[prop];
2489
+ if (state.finalized_ || !isDraftable(value)) return value;
2490
+ if (value === peek(state.base_, prop)) {
2491
+ prepareCopy(state);
2492
+ return state.copy_[prop] = createProxy(value, state);
2493
+ }
2494
+ return value;
2495
+ },
2496
+ has(state, prop) {
2497
+ return prop in latest(state);
2498
+ },
2499
+ ownKeys(state) {
2500
+ return Reflect.ownKeys(latest(state));
2501
+ },
2502
+ set(state, prop, value) {
2503
+ const desc = getDescriptorFromProto(latest(state), prop);
2504
+ if (desc?.set) {
2505
+ desc.set.call(state.draft_, value);
2506
+ return true;
2507
+ }
2508
+ if (!state.modified_) {
2509
+ const current2 = peek(latest(state), prop);
2510
+ const currentState = current2?.[DRAFT_STATE];
2511
+ if (currentState && currentState.base_ === value) {
2512
+ state.copy_[prop] = value;
2513
+ state.assigned_[prop] = false;
2514
+ return true;
2515
+ }
2516
+ if (is(value, current2) && (value !== void 0 || has(state.base_, prop))) return true;
2517
+ prepareCopy(state);
2518
+ markChanged(state);
2519
+ }
2520
+ if (state.copy_[prop] === value && (value !== void 0 || prop in state.copy_) || Number.isNaN(value) && Number.isNaN(state.copy_[prop])) return true;
2521
+ state.copy_[prop] = value;
2522
+ state.assigned_[prop] = true;
2523
+ return true;
2524
+ },
2525
+ deleteProperty(state, prop) {
2526
+ if (peek(state.base_, prop) !== void 0 || prop in state.base_) {
2527
+ state.assigned_[prop] = false;
2528
+ prepareCopy(state);
2529
+ markChanged(state);
2530
+ } else delete state.assigned_[prop];
2531
+ if (state.copy_) delete state.copy_[prop];
2532
+ return true;
2533
+ },
2534
+ getOwnPropertyDescriptor(state, prop) {
2535
+ const owner = latest(state);
2536
+ const desc = Reflect.getOwnPropertyDescriptor(owner, prop);
2537
+ if (!desc) return desc;
2538
+ return {
2539
+ writable: true,
2540
+ configurable: state.type_ !== 1 || prop !== "length",
2541
+ enumerable: desc.enumerable,
2542
+ value: owner[prop]
2543
+ };
2544
+ },
2545
+ defineProperty() {
2546
+ die(11);
2547
+ },
2548
+ getPrototypeOf(state) {
2549
+ return getPrototypeOf(state.base_);
2550
+ },
2551
+ setPrototypeOf() {
2552
+ die(12);
2553
+ }
2554
+ };
2555
+ var arrayTraps = {};
2556
+ each(objectTraps, (key, fn) => {
2557
+ arrayTraps[key] = function() {
2558
+ arguments[0] = arguments[0][0];
2559
+ return fn.apply(this, arguments);
2560
+ };
2561
+ });
2562
+ arrayTraps.deleteProperty = function(state, prop) {
2563
+ if (isNaN(parseInt(prop))) die(13);
2564
+ return arrayTraps.set.call(this, state, prop, void 0);
2565
+ };
2566
+ arrayTraps.set = function(state, prop, value) {
2567
+ if (prop !== "length" && isNaN(parseInt(prop))) die(14);
2568
+ return objectTraps.set.call(this, state[0], prop, value, state[0]);
2569
+ };
2570
+ function peek(draft, prop) {
2571
+ const state = draft[DRAFT_STATE];
2572
+ return (state ? latest(state) : draft)[prop];
2573
+ }
2574
+ function readPropFromProto(state, source, prop) {
2575
+ const desc = getDescriptorFromProto(source, prop);
2576
+ return desc ? `value` in desc ? desc.value : desc.get?.call(state.draft_) : void 0;
2577
+ }
2578
+ function getDescriptorFromProto(source, prop) {
2579
+ if (!(prop in source)) return void 0;
2580
+ let proto = getPrototypeOf(source);
2581
+ while (proto) {
2582
+ const desc = Object.getOwnPropertyDescriptor(proto, prop);
2583
+ if (desc) return desc;
2584
+ proto = getPrototypeOf(proto);
2585
+ }
2586
+ }
2587
+ function markChanged(state) {
2588
+ if (!state.modified_) {
2589
+ state.modified_ = true;
2590
+ if (state.parent_) markChanged(state.parent_);
2591
+ }
2592
+ }
2593
+ function prepareCopy(state) {
2594
+ if (!state.copy_) state.copy_ = shallowCopy(state.base_, state.scope_.immer_.useStrictShallowCopy_);
2595
+ }
2596
+ var Immer2 = class {
2597
+ constructor(config) {
2598
+ this.autoFreeze_ = true;
2599
+ this.useStrictShallowCopy_ = false;
2600
+ this.useStrictIteration_ = true;
2601
+ /**
2602
+ * The `produce` function takes a value and a "recipe function" (whose
2603
+ * return value often depends on the base state). The recipe function is
2604
+ * free to mutate its first argument however it wants. All mutations are
2605
+ * only ever applied to a __copy__ of the base state.
2606
+ *
2607
+ * Pass only a function to create a "curried producer" which relieves you
2608
+ * from passing the recipe function every time.
2609
+ *
2610
+ * Only plain objects and arrays are made mutable. All other objects are
2611
+ * considered uncopyable.
2612
+ *
2613
+ * Note: This function is __bound__ to its `Immer` instance.
2614
+ *
2615
+ * @param {any} base - the initial state
2616
+ * @param {Function} recipe - function that receives a proxy of the base state as first argument and which can be freely modified
2617
+ * @param {Function} patchListener - optional function that will be called with all the patches produced here
2618
+ * @returns {any} a new state, or the initial state if nothing was modified
2619
+ */
2620
+ this.produce = (base, recipe, patchListener) => {
2621
+ if (typeof base === "function" && typeof recipe !== "function") {
2622
+ const defaultBase = recipe;
2623
+ recipe = base;
2624
+ const self = this;
2625
+ return function curriedProduce(base2 = defaultBase, ...args) {
2626
+ return self.produce(base2, (draft) => recipe.call(this, draft, ...args));
2627
+ };
2628
+ }
2629
+ if (typeof recipe !== "function") die(6);
2630
+ if (patchListener !== void 0 && typeof patchListener !== "function") die(7);
2631
+ let result;
2632
+ if (isDraftable(base)) {
2633
+ const scope = enterScope(this);
2634
+ const proxy = createProxy(base, void 0);
2635
+ let hasError = true;
2636
+ try {
2637
+ result = recipe(proxy);
2638
+ hasError = false;
2639
+ } finally {
2640
+ if (hasError) revokeScope(scope);
2641
+ else leaveScope(scope);
2642
+ }
2643
+ usePatchesInScope(scope, patchListener);
2644
+ return processResult(result, scope);
2645
+ } else if (!base || typeof base !== "object") {
2646
+ result = recipe(base);
2647
+ if (result === void 0) result = base;
2648
+ if (result === NOTHING) result = void 0;
2649
+ if (this.autoFreeze_) freeze(result, true);
2650
+ if (patchListener) {
2651
+ const p = [];
2652
+ const ip = [];
2653
+ getPlugin("Patches").generateReplacementPatches_(base, result, p, ip);
2654
+ patchListener(p, ip);
2655
+ }
2656
+ return result;
2657
+ } else die(1, base);
2658
+ };
2659
+ this.produceWithPatches = (base, recipe) => {
2660
+ if (typeof base === "function") return (state, ...args) => this.produceWithPatches(state, (draft) => base(draft, ...args));
2661
+ let patches, inversePatches;
2662
+ return [
2663
+ this.produce(base, recipe, (p, ip) => {
2664
+ patches = p;
2665
+ inversePatches = ip;
2666
+ }),
2667
+ patches,
2668
+ inversePatches
2669
+ ];
2670
+ };
2671
+ if (typeof config?.autoFreeze === "boolean") this.setAutoFreeze(config.autoFreeze);
2672
+ if (typeof config?.useStrictShallowCopy === "boolean") this.setUseStrictShallowCopy(config.useStrictShallowCopy);
2673
+ if (typeof config?.useStrictIteration === "boolean") this.setUseStrictIteration(config.useStrictIteration);
2674
+ }
2675
+ createDraft(base) {
2676
+ if (!isDraftable(base)) die(8);
2677
+ if (isDraft(base)) base = current(base);
2678
+ const scope = enterScope(this);
2679
+ const proxy = createProxy(base, void 0);
2680
+ proxy[DRAFT_STATE].isManual_ = true;
2681
+ leaveScope(scope);
2682
+ return proxy;
2683
+ }
2684
+ finishDraft(draft, patchListener) {
2685
+ const state = draft && draft[DRAFT_STATE];
2686
+ if (!state || !state.isManual_) die(9);
2687
+ const { scope_: scope } = state;
2688
+ usePatchesInScope(scope, patchListener);
2689
+ return processResult(void 0, scope);
2690
+ }
2691
+ /**
2692
+ * Pass true to automatically freeze all copies created by Immer.
2693
+ *
2694
+ * By default, auto-freezing is enabled.
2695
+ */
2696
+ setAutoFreeze(value) {
2697
+ this.autoFreeze_ = value;
2698
+ }
2699
+ /**
2700
+ * Pass true to enable strict shallow copy.
2701
+ *
2702
+ * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
2703
+ */
2704
+ setUseStrictShallowCopy(value) {
2705
+ this.useStrictShallowCopy_ = value;
2706
+ }
2707
+ /**
2708
+ * Pass false to use faster iteration that skips non-enumerable properties
2709
+ * but still handles symbols for compatibility.
2710
+ *
2711
+ * By default, strict iteration is enabled (includes all own properties).
2712
+ */
2713
+ setUseStrictIteration(value) {
2714
+ this.useStrictIteration_ = value;
2715
+ }
2716
+ shouldUseStrictIteration() {
2717
+ return this.useStrictIteration_;
2718
+ }
2719
+ applyPatches(base, patches) {
2720
+ let i;
2721
+ for (i = patches.length - 1; i >= 0; i--) {
2722
+ const patch = patches[i];
2723
+ if (patch.path.length === 0 && patch.op === "replace") {
2724
+ base = patch.value;
2725
+ break;
2726
+ }
2727
+ }
2728
+ if (i > -1) patches = patches.slice(i + 1);
2729
+ const applyPatchesImpl = getPlugin("Patches").applyPatches_;
2730
+ if (isDraft(base)) return applyPatchesImpl(base, patches);
2731
+ return this.produce(base, (draft) => applyPatchesImpl(draft, patches));
2732
+ }
2733
+ };
2734
+ function createProxy(value, parent) {
2735
+ const draft = isMap(value) ? getPlugin("MapSet").proxyMap_(value, parent) : isSet(value) ? getPlugin("MapSet").proxySet_(value, parent) : createProxyProxy(value, parent);
2736
+ (parent ? parent.scope_ : getCurrentScope()).drafts_.push(draft);
2737
+ return draft;
2738
+ }
2739
+ function current(value) {
2740
+ if (!isDraft(value)) die(10, value);
2741
+ return currentImpl(value);
2742
+ }
2743
+ function currentImpl(value) {
2744
+ if (!isDraftable(value) || isFrozen(value)) return value;
2745
+ const state = value[DRAFT_STATE];
2746
+ let copy;
2747
+ let strict = true;
2748
+ if (state) {
2749
+ if (!state.modified_) return state.base_;
2750
+ state.finalized_ = true;
2751
+ copy = shallowCopy(value, state.scope_.immer_.useStrictShallowCopy_);
2752
+ strict = state.scope_.immer_.shouldUseStrictIteration();
2753
+ } else copy = shallowCopy(value, true);
2754
+ each(copy, (key, childValue) => {
2755
+ set(copy, key, currentImpl(childValue));
2756
+ }, strict);
2757
+ if (state) state.finalized_ = false;
2758
+ return copy;
2759
+ }
2760
+ var immer = new Immer2();
2761
+ immer.produce;
2762
+ var setAutoFreeze = /* @__PURE__ */ immer.setAutoFreeze.bind(immer);
2763
+ const produce = new Immer2({
900
2764
  autoFreeze: false,
901
2765
  useStrictShallowCopy: true
902
2766
  }).produce;
903
2767
  //#endregion
904
- //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.1/node_modules/loro-mirror/dist/core/debounce-timer.js
2768
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/core/debounce-timer.js
905
2769
  /**
906
2770
  * Deadline-based debounce timer.
907
2771
  *
@@ -959,7 +2823,7 @@ var DebounceTimer = class {
959
2823
  }
960
2824
  };
961
2825
  //#endregion
962
- //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.1/node_modules/loro-mirror/dist/core/ephemeral.js
2826
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/core/ephemeral.js
963
2827
  /**
964
2828
  * Manages ephemeral patches: storage, composition, path resolution, and finalization.
965
2829
  */
@@ -1234,7 +3098,7 @@ var EphemeralPatchManager = class {
1234
3098
  }
1235
3099
  };
1236
3100
  //#endregion
1237
- //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.1/node_modules/loro-mirror/dist/core/tree-utils.js
3101
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/core/tree-utils.js
1238
3102
  function normalizeTreeJson(input, options) {
1239
3103
  if (!Array.isArray(input)) return [];
1240
3104
  return input.map((node) => normalizeTreeNode(node, options));
@@ -1257,7 +3121,7 @@ function isPlainRecord(value) {
1257
3121
  return typeof value === "object" && value !== null && !Array.isArray(value);
1258
3122
  }
1259
3123
  //#endregion
1260
- //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.1/node_modules/loro-mirror/dist/core/loroEventApply.js
3124
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/core/loroEventApply.js
1261
3125
  function isJSONObject(v) {
1262
3126
  return typeof v === "object" && v !== null && !Array.isArray(v);
1263
3127
  }
@@ -1679,7 +3543,7 @@ function isIgnoredByAncestor(id, ignoreSet, getContainerById) {
1679
3543
  return false;
1680
3544
  }
1681
3545
  //#endregion
1682
- //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.1/node_modules/loro-mirror/dist/core/diff.js
3546
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/core/diff.js
1683
3547
  /**
1684
3548
  * Finds the longest increasing subsequence of a sequence of numbers
1685
3549
  * @param sequence The sequence of numbers
@@ -2410,7 +4274,7 @@ function diffMap(doc, oldState, newState, containerId, schema, inferOptions) {
2410
4274
  return changes;
2411
4275
  }
2412
4276
  //#endregion
2413
- //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.1/node_modules/loro-mirror/dist/core/mirror.js
4277
+ //#region ../../node_modules/.pnpm/loro-mirror@2.3.3_patch_hash=a551a0e4aa4f61ec88b0d9e970a183b5ee2955107a2e0bb03b378bc510c2f395_loro-crdt@1.16.4/node_modules/loro-mirror/dist/core/mirror.js
2414
4278
  /**
2415
4279
  * Mirror core functionality for bidirectional sync between app state and Loro CRDT
2416
4280
  */
@@ -3905,6 +5769,220 @@ function mergeInitialIntoBaseWithSchema(base, init, rootSchema) {
3905
5769
  }
3906
5770
  }
3907
5771
  //#endregion
5772
+ //#region ../medeo-dsl/src/schema/codec.ts
5773
+ function isInvalidAtomic(value) {
5774
+ return typeof value === "object" && value !== null && "invalid" in value && value.invalid === true;
5775
+ }
5776
+ function codec(encode, decode) {
5777
+ return {
5778
+ encode: (v) => isInvalidAtomic(v) ? v.raw : encode(v),
5779
+ decode: (raw) => {
5780
+ try {
5781
+ return decode(raw);
5782
+ } catch (error) {
5783
+ return {
5784
+ invalid: true,
5785
+ raw,
5786
+ reason: String(error)
5787
+ };
5788
+ }
5789
+ }
5790
+ };
5791
+ }
5792
+ /** A Clip's time anchor; the Clip holding it is the anchored end. */
5793
+ const timeAnchorCodec = codec((v) => {
5794
+ assertTimeAnchor(v);
5795
+ return JSON.stringify({
5796
+ to: v.to,
5797
+ offsetMs: v.offsetMs,
5798
+ fallback_abs_ms: v.fallback_abs_ms
5799
+ });
5800
+ }, (raw) => {
5801
+ const v = JSON.parse(raw);
5802
+ assertTimeAnchor(v);
5803
+ return v;
5804
+ });
5805
+ /** A segment selection as stored: a run's Cursors as their native bytes in unpadded base64url. */
5806
+ function encodeSelection(v) {
5807
+ return {
5808
+ audioScriptId: v.audioScriptId,
5809
+ segmentId: v.segmentId,
5810
+ ...v.start === void 0 || v.end === void 0 ? {} : {
5811
+ start: bytesToBase64url(v.start.encode()),
5812
+ end: bytesToBase64url(v.end.encode())
5813
+ }
5814
+ };
5815
+ }
5816
+ function decodeSelection(v) {
5817
+ if (!v || typeof v !== "object") throw new Error("Expected a segment selection");
5818
+ const { start, end, ...rest } = v;
5819
+ if (start === void 0 && end === void 0) return rest;
5820
+ if (typeof start !== "string" || typeof end !== "string") throw new Error("Expected encoded Cursor pair");
5821
+ return {
5822
+ ...rest,
5823
+ start: Cursor.decode(base64urlToBytes(start)),
5824
+ end: Cursor.decode(base64urlToBytes(end))
5825
+ };
5826
+ }
5827
+ /** A Caption's selection. */
5828
+ const captionContentCodec = codec((v) => {
5829
+ assertCaptionContent(v);
5830
+ return JSON.stringify(encodeSelection(v));
5831
+ }, (raw) => {
5832
+ const value = decodeSelection(JSON.parse(raw));
5833
+ assertCaptionContent(value);
5834
+ return value;
5835
+ });
5836
+ /** A PhoneticScript's selection and what to synthesize for it, stored as one string so they move together. */
5837
+ const phonemeCodec = codec((v) => {
5838
+ assertPhoneme(v);
5839
+ return JSON.stringify({
5840
+ ...encodeSelection(v),
5841
+ ...v.phonemeScript === void 0 ? {} : { phonemeScript: v.phonemeScript }
5842
+ });
5843
+ }, (raw) => {
5844
+ const value = decodeSelection(JSON.parse(raw));
5845
+ assertPhoneme(value);
5846
+ return value;
5847
+ });
5848
+ /** A Clip's sequence marker is stored as one string, so it is taken or replaced whole. */
5849
+ const seqMarkerCodec = codec((v) => {
5850
+ assertSeqMarker(v);
5851
+ return JSON.stringify({
5852
+ inMs: v.inMs,
5853
+ outMs: v.outMs,
5854
+ ...v.rate === void 0 ? {} : { rate: v.rate },
5855
+ ...v.fillTimeline === void 0 ? {} : { fillTimeline: v.fillTimeline }
5856
+ });
5857
+ }, (raw) => {
5858
+ const v = JSON.parse(raw);
5859
+ assertSeqMarker(v);
5860
+ return v;
5861
+ });
5862
+ //#endregion
5863
+ //#region ../medeo-dsl/src/schema/loro-shape.ts
5864
+ const optional = { required: false };
5865
+ const mergeable = { mergeableMapChildContainers: true };
5866
+ const strings = (keys) => Object.fromEntries(keys.map((key) => [key, schema.String()]));
5867
+ const relation = (keys) => schema.LoroMapRecord(schema.LoroMap(strings(keys)), mergeable);
5868
+ const transform = (codec) => ({
5869
+ ...codec,
5870
+ isEqual: "encoded-value-equality",
5871
+ validateEncodedType: true
5872
+ });
5873
+ /** One field stored as one encoded string, so it is taken or replaced whole. */
5874
+ const atomicValue = (codec) => schema.String().transform(transform(codec));
5875
+ const optionalAtomicValue = (codec) => schema.String(optional).transform(transform(codec));
5876
+ /**
5877
+ * Only direct children inherit mergeable identity. Text and ordinary entity rows keep normal
5878
+ * identities, so deleting a row also drops what a peer wrote into it concurrently: a relation an
5879
+ * entity holds at most one of is a field of that row and never outlives it.
5880
+ */
5881
+ const medeoDslLoroShape = schema({
5882
+ "timeline-entities": schema.LoroMapRecord(schema.LoroMap({})),
5883
+ "track-entities": schema.LoroMapRecord(schema.LoroMap({
5884
+ role: schema.String(),
5885
+ hidden: schema.Boolean(optional)
5886
+ })),
5887
+ "clip-entities": schema.LoroMapRecord(schema.LoroMap({
5888
+ seqMarker: atomicValue(seqMarkerCodec),
5889
+ volume: schema.Number(optional),
5890
+ source: schema.String(),
5891
+ anchor: optionalAtomicValue(timeAnchorCodec)
5892
+ })),
5893
+ "media-entities": schema.LoroMapRecord(schema.LoroMap({
5894
+ kind: schema.String(),
5895
+ system: schema.String(),
5896
+ key: schema.String(),
5897
+ storageKey: schema.String(optional),
5898
+ durationMs: schema.Number(optional),
5899
+ digest: schema.String(optional)
5900
+ }), mergeable),
5901
+ "audio-script-entities": schema.LoroMapRecord(schema.LoroMap({
5902
+ segments: schema.LoroMovableList(schema.LoroMap({
5903
+ id: schema.String(),
5904
+ text: schema.LoroText(),
5905
+ startMs: schema.Number(optional),
5906
+ endMs: schema.Number(optional)
5907
+ }), (segment) => segment.id),
5908
+ defaultLanguage: schema.String(optional),
5909
+ system: schema.String(optional),
5910
+ key: schema.String(optional),
5911
+ storageKey: schema.String(optional),
5912
+ digest: schema.String(optional)
5913
+ })),
5914
+ "phonetic-script-entities": schema.LoroMapRecord(schema.LoroMap({
5915
+ phoneme: atomicValue(phonemeCodec),
5916
+ system: schema.String(optional),
5917
+ key: schema.String(optional),
5918
+ storageKey: schema.String(optional),
5919
+ digest: schema.String(optional)
5920
+ })),
5921
+ "caption-entities": schema.LoroMapRecord(schema.LoroMap({
5922
+ selection: optionalAtomicValue(captionContentCodec),
5923
+ text: schema.LoroText(optional),
5924
+ style: schema.LoroMap({
5925
+ font: schema.LoroMap({
5926
+ system: schema.String(),
5927
+ key: schema.String()
5928
+ }, optional),
5929
+ fontSize: schema.Number(optional),
5930
+ fontColor: schema.String(optional),
5931
+ fontWeight: schema.Number(optional),
5932
+ entranceAnimation: schema.String(optional),
5933
+ entranceAnimationDurationMs: schema.Number(optional),
5934
+ strokeColor: schema.String(optional),
5935
+ strokeWidth: schema.Number(optional),
5936
+ positionX: schema.Number(optional),
5937
+ positionY: schema.Number(optional)
5938
+ }, {
5939
+ ...optional,
5940
+ ...mergeable
5941
+ })
5942
+ }, mergeable)),
5943
+ "voice-entities": schema.LoroMapRecord(schema.LoroMap({
5944
+ system: schema.String(),
5945
+ key: schema.String(),
5946
+ name: schema.String(optional)
5947
+ }), mergeable),
5948
+ "contain-relations": schema.LoroTree(schema.LoroMap({ entityId: schema.String() })),
5949
+ "voice-timbre-relations": relation(["recordingId", "voiceId"]),
5950
+ "derived-from-relations": schema.LoroMapRecord(schema.LoroMap({
5951
+ entityId: schema.String(),
5952
+ sourceId: schema.String(),
5953
+ sourceDigest: schema.String(optional)
5954
+ }), mergeable)
5955
+ });
5956
+ //#endregion
5957
+ //#region ../medeo-dsl/src/schema/document-format.ts
5958
+ /** Format discrimination does not register containers or alter the document. */
5959
+ function documentFormat(doc) {
5960
+ const roots = doc.getShallowValue();
5961
+ const legacy = [
5962
+ "medeo",
5963
+ "timeline",
5964
+ "tracks",
5965
+ "part_library"
5966
+ ].some((key) => Object.hasOwn(roots, key));
5967
+ const dsl = Object.keys(roots).some((key) => key.endsWith("-entities") || key.endsWith("-relations"));
5968
+ return legacy && dsl ? "mixed" : legacy ? "legacy" : dsl ? "dsl" : "unknown";
5969
+ }
5970
+ var UnsupportedDocumentFormatError = class extends Error {
5971
+ code = "unsupported_document_format";
5972
+ constructor() {
5973
+ super("Expected a new DSL document; legacy, mixed or uninitialized content is not supported");
5974
+ this.name = "UnsupportedDocumentFormatError";
5975
+ }
5976
+ };
5977
+ /** Run after initial import, before opening an editable handle. Empty new documents still have one Timeline. */
5978
+ function assertDslDocument(doc) {
5979
+ if (documentFormat(doc) !== "dsl" || doc.getMap("timeline-entities").keys().length !== 1) throw new UnsupportedDocumentFormatError();
5980
+ }
5981
+ //#endregion
5982
+ //#region ../medeo-dsl/src/schema/text-styles.ts
5983
+ /** How rich-text marks extend at their edges: a language runs on into text typed after it. */
5984
+ const textStyles = { language: { expand: "after" } };
5985
+ //#endregion
3908
5986
  //#region src/dsl/document/read.ts
3909
5987
  /** Looking up a missing root must not create it. */
3910
5988
  function rootMap(doc, name) {
@@ -4408,7 +6486,10 @@ function applyMutations(tx, mutations) {
4408
6486
  delete rows[m.table][m.id];
4409
6487
  break;
4410
6488
  case "insert-segment":
4411
- tx.insertSegment(m.audioScriptId, m.segmentId, m.text, m.index);
6489
+ tx.insertSegment(m.audioScriptId, m.segmentId, m.text, m.index, m.startMs === void 0 && m.endMs === void 0 ? void 0 : {
6490
+ startMs: m.startMs,
6491
+ endMs: m.endMs
6492
+ });
4412
6493
  break;
4413
6494
  case "move-segment":
4414
6495
  tx.moveSegment(m.audioScriptId, m.segmentId, m.index);
@@ -4666,18 +6747,21 @@ function runTransaction(doc, mirror, edit, options, setReject) {
4666
6747
  editCaptionText(captionId, edits, expectedBodyId) {
4667
6748
  editBody({ captionId }, edits, expectedBodyId);
4668
6749
  },
4669
- insertSegment(audioScriptId, segmentId, text, index) {
6750
+ insertSegment(audioScriptId, segmentId, text, index, time) {
4670
6751
  tracked.run(() => {
4671
6752
  assertId(segmentId);
4672
6753
  if (typeof text !== "string") throw new Error("Segment text is a string");
6754
+ const segment = {
6755
+ id: segmentId,
6756
+ text,
6757
+ ...time
6758
+ };
6759
+ assertScriptSegment(segment);
4673
6760
  const segments = segmentsOf(audioScriptId);
4674
6761
  if (segments.some((segment) => segment.id === segmentId)) throw new Error(`Segment already exists: ${segmentId}`);
4675
6762
  const at = index ?? segments.length;
4676
6763
  if (!Number.isSafeInteger(at) || at < 0 || at > segments.length) throw new Error("Invalid segment index");
4677
- segments.splice(at, 0, {
4678
- id: segmentId,
4679
- text
4680
- });
6764
+ segments.splice(at, 0, segment);
4681
6765
  });
4682
6766
  },
4683
6767
  moveSegment(audioScriptId, segmentId, index) {
@@ -5054,6 +7138,150 @@ var MedeoDsl = class MedeoDsl {
5054
7138
  }
5055
7139
  };
5056
7140
  //#endregion
7141
+ //#region src/dsl/projection/audio-scripts.ts
7142
+ /**
7143
+ * The scripts a recording says. It follows derived-from from the recording; a PhoneticScript is a
7144
+ * variant, so its words are the base its phoneme names, and derived-from is not followed past it.
7145
+ * When nothing is found that way, a script read off the recording itself is what it says.
7146
+ */
7147
+ function spokenScripts(snapshot, recordingId) {
7148
+ const relations = Object.values(snapshot["derived-from-relations"]);
7149
+ const found = /* @__PURE__ */ new Map();
7150
+ const seen = /* @__PURE__ */ new Set();
7151
+ const visit = (id, phoneticScriptId) => {
7152
+ if (seen.has(id)) return;
7153
+ seen.add(id);
7154
+ if (snapshot["audio-script-entities"][id]) {
7155
+ if (!found.has(id)) found.set(id, phoneticScriptId);
7156
+ return;
7157
+ }
7158
+ const phonetic = snapshot["phonetic-script-entities"][id];
7159
+ if (phonetic) {
7160
+ visit(phonetic.phoneme.audioScriptId, id);
7161
+ return;
7162
+ }
7163
+ for (const r of relations) if (r.entityId === id) visit(r.sourceId, phoneticScriptId);
7164
+ };
7165
+ visit(recordingId);
7166
+ if (!found.size) {
7167
+ for (const r of relations) if (r.sourceId === recordingId && snapshot["audio-script-entities"][r.entityId]) found.set(r.entityId, void 0);
7168
+ }
7169
+ return [...found].map(([audioScriptId, phoneticScriptId]) => phoneticScriptId === void 0 ? { audioScriptId } : {
7170
+ audioScriptId,
7171
+ phoneticScriptId
7172
+ });
7173
+ }
7174
+ /** Every AudioScript in the document with its PhoneticScripts, the Speech Clips saying it and the Caption Clips showing it. */
7175
+ function toAudioScriptViews(snapshot) {
7176
+ const views = /* @__PURE__ */ new Map();
7177
+ const segmentIndex = (scriptId, segmentId) => {
7178
+ const index = snapshot["audio-script-entities"][scriptId]?.segments.findIndex((s) => s.id === segmentId) ?? -1;
7179
+ return index < 0 ? void 0 : index;
7180
+ };
7181
+ for (const [id, script] of Object.entries(snapshot["audio-script-entities"])) views.set(id, {
7182
+ id,
7183
+ segments: script.segments.map((segment) => {
7184
+ const rich = snapshot.richText[segment.id];
7185
+ const language = rich ? markedLanguage(langsFromDelta(rich.delta)) : void 0;
7186
+ return {
7187
+ id: segment.id,
7188
+ text: segment.text,
7189
+ ...language === void 0 ? {} : { language },
7190
+ ...segment.startMs === void 0 ? {} : {
7191
+ startMs: segment.startMs,
7192
+ endMs: segment.endMs
7193
+ }
7194
+ };
7195
+ }),
7196
+ sourceMediaIds: [],
7197
+ phoneticScripts: [],
7198
+ speeches: [],
7199
+ captions: []
7200
+ });
7201
+ for (const r of Object.values(snapshot["derived-from-relations"])) if (snapshot["media-entities"][r.sourceId]) views.get(r.entityId)?.sourceMediaIds.push(r.sourceId);
7202
+ for (const [id, phonetic] of Object.entries(snapshot["phonetic-script-entities"])) {
7203
+ const { audioScriptId, segmentId, phonemeScript } = phonetic.phoneme;
7204
+ const { digest } = phonetic;
7205
+ const segment = segmentIndex(audioScriptId, segmentId);
7206
+ const text = snapshot.phoneticText[id]?.text;
7207
+ views.get(audioScriptId)?.phoneticScripts.push({
7208
+ id,
7209
+ ...segment === void 0 ? {} : { segment },
7210
+ ...text === void 0 ? {} : { text },
7211
+ ...phonemeScript === void 0 ? {} : { phonemeScript },
7212
+ ...digest === void 0 ? {} : { digest }
7213
+ });
7214
+ }
7215
+ const layout = resolveDslLayout(snapshot);
7216
+ for (const view of views.values()) placeTranscript(snapshot, layout, view);
7217
+ const timbres = Object.values(snapshot["voice-timbre-relations"]);
7218
+ for (const track of layout.tracks) for (const { clipId } of track.clips) {
7219
+ const source = snapshot["clip-entities"][clipId]?.source;
7220
+ if (!source) continue;
7221
+ if (snapshot["media-entities"][source]?.kind === "voiceover-recording") {
7222
+ const voices = timbres.filter((r) => r.recordingId === source).flatMap((r) => {
7223
+ const voice = snapshot["voice-entities"][r.voiceId];
7224
+ if (!voice) return [];
7225
+ return [voice.name === void 0 ? {
7226
+ voiceId: r.voiceId,
7227
+ key: voice.key
7228
+ } : {
7229
+ voiceId: r.voiceId,
7230
+ key: voice.key,
7231
+ name: voice.name
7232
+ }];
7233
+ });
7234
+ for (const spoken of spokenScripts(snapshot, source)) {
7235
+ const applied = appliedSpeech(snapshot, source, spoken);
7236
+ views.get(spoken.audioScriptId)?.speeches.push({
7237
+ clipId,
7238
+ recordingId: source,
7239
+ ...spoken.phoneticScriptId === void 0 ? {} : { phoneticScriptId: spoken.phoneticScriptId },
7240
+ voices,
7241
+ ...applied === void 0 ? {} : { applied }
7242
+ });
7243
+ }
7244
+ continue;
7245
+ }
7246
+ const caption = snapshot["caption-entities"][source];
7247
+ if (!caption?.selection || caption.text !== void 0 || !snapshot.captionText[source]) continue;
7248
+ const { audioScriptId, segmentId } = caption.selection;
7249
+ const segment = segmentIndex(audioScriptId, segmentId);
7250
+ if (segment !== void 0) views.get(audioScriptId)?.captions.push({
7251
+ clipId,
7252
+ captionId: source,
7253
+ segment
7254
+ });
7255
+ }
7256
+ return [...views.values()];
7257
+ }
7258
+ /**
7259
+ * A transcript's segments on the Timeline: a segment's time is in the medium the script was read
7260
+ * off, so it lands where the earliest Clip playing that medium holds that moment in its window.
7261
+ */
7262
+ function placeTranscript(snapshot, layout, view) {
7263
+ if (!view.sourceMediaIds.length) return;
7264
+ const plays = layout.tracks.flatMap((track) => track.clips).filter((clip) => view.sourceMediaIds.includes(snapshot["clip-entities"][clip.clipId]?.source ?? "")).sort((a, b) => a.startMs - b.startMs);
7265
+ for (const segment of view.segments) {
7266
+ const at = segment.startMs;
7267
+ if (at === void 0) continue;
7268
+ const clip = plays.find((c) => c.inMs <= at && at < c.outMs);
7269
+ if (clip) segment.timelineMs = Math.round(clip.startMs + (at - clip.inMs) / clip.rate);
7270
+ }
7271
+ }
7272
+ /**
7273
+ * Whether a recording still matches what it was synthesized from: the digest its derived-from
7274
+ * records against the source's file digest now. A recording derived from a script directly is
7275
+ * not judged: a written script has no file, and a transcript's file is what it was read from,
7276
+ * not what a take was synthesized from (D190).
7277
+ */
7278
+ function appliedSpeech(snapshot, recordingId, spoken) {
7279
+ const sourceId = spoken.phoneticScriptId ?? spoken.audioScriptId;
7280
+ const recorded = Object.values(snapshot["derived-from-relations"]).find((r) => r.entityId === recordingId && r.sourceId === sourceId)?.sourceDigest;
7281
+ const current = spoken.phoneticScriptId === void 0 ? void 0 : snapshot["phonetic-script-entities"][sourceId]?.digest;
7282
+ return recorded === void 0 || current === void 0 ? void 0 : recorded === current;
7283
+ }
7284
+ //#endregion
5057
7285
  //#region src/dsl/voiceover-actions.ts
5058
7286
  function voiceoverPlan(s, input, result) {
5059
7287
  if (requireTrack(s, input.trackId).role !== "speech" || input.media.kind !== "voiceover-recording") throw new Error("Voiceover requires a speech Track and a recording");
@@ -5154,7 +7382,7 @@ function voiceoverPlan(s, input, result) {
5154
7382
  mutations.push(...placementMutations(s, result.clipId, input.placement));
5155
7383
  uniqueIds(result.captionClipIds);
5156
7384
  const retained = new Set(result.captionClipIds);
5157
- const oldCaptions = anchoredTo(s, new Set([result.clipId])).filter((id) => requireTrack(s, trackOf(s, id)).role === "caption");
7385
+ const oldCaptions = existing ? captionsShowing(s, existing.source) : [];
5158
7386
  mutations.push(...deleteClips(s, oldCaptions.filter((id) => !retained.has(id)), "cascade"));
5159
7387
  const placement = mutations.find((m) => m.type === "patch-entity" && m.table === "clip-entities" && m.id === result.clipId && "anchor" in m.patch);
5160
7388
  const anchor = placement?.type === "patch-entity" && placement.table === "clip-entities" ? placement.patch.anchor : void 0;
@@ -5225,6 +7453,33 @@ function voiceoverPlan(s, input, result) {
5225
7453
  });
5226
7454
  return mutations;
5227
7455
  }
7456
+ /**
7457
+ * Caption Clips showing what a recording says (D183): their Caption selects the run of the segment
7458
+ * the PhoneticScript it was spoken from is written for, or any segment of the script it was read
7459
+ * from directly.
7460
+ */
7461
+ function captionsShowing(s, recordingId) {
7462
+ const said = spokenScripts(s, recordingId).map(({ audioScriptId, phoneticScriptId }) => {
7463
+ if (phoneticScriptId === void 0) return { audioScriptId };
7464
+ const { segmentId } = s["phonetic-script-entities"][phoneticScriptId].phoneme;
7465
+ return {
7466
+ audioScriptId,
7467
+ segmentId,
7468
+ run: s.phoneticText[phoneticScriptId]
7469
+ };
7470
+ });
7471
+ return Object.entries(s["clip-entities"]).flatMap(([id, clip]) => {
7472
+ const selection = s["caption-entities"][clip.source]?.selection;
7473
+ const shown = s.captionText[clip.source];
7474
+ if (!selection) return [];
7475
+ return said.some((words) => {
7476
+ if (selection.audioScriptId !== words.audioScriptId) return false;
7477
+ if (!("segmentId" in words)) return true;
7478
+ if (selection.segmentId !== words.segmentId || !shown || !words.run) return false;
7479
+ return shown.start < words.run.end && words.run.start < shown.end;
7480
+ }) && requireTrack(s, trackOf(s, id)).role === "caption" ? [id] : [];
7481
+ });
7482
+ }
5228
7483
  //#endregion
5229
7484
  //#region src/dsl/dsl-editor.ts
5230
7485
  /** Business edits write DSL facts in one audited transaction; layout is derived on read. */
@@ -5743,132 +7998,6 @@ function createInitialMedeoDsl(options = {}) {
5743
7998
  }
5744
7999
  }
5745
8000
  //#endregion
5746
- //#region src/dsl/projection/audio-scripts.ts
5747
- /**
5748
- * The scripts a recording says. It follows derived-from from the recording; a PhoneticScript is a
5749
- * variant, so its words are the base its phoneme names, and derived-from is not followed past it.
5750
- * When nothing is found that way, a script read off the recording itself is what it says.
5751
- */
5752
- function spokenScripts(snapshot, recordingId) {
5753
- const relations = Object.values(snapshot["derived-from-relations"]);
5754
- const found = /* @__PURE__ */ new Map();
5755
- const seen = /* @__PURE__ */ new Set();
5756
- const visit = (id, phoneticScriptId) => {
5757
- if (seen.has(id)) return;
5758
- seen.add(id);
5759
- if (snapshot["audio-script-entities"][id]) {
5760
- if (!found.has(id)) found.set(id, phoneticScriptId);
5761
- return;
5762
- }
5763
- const phonetic = snapshot["phonetic-script-entities"][id];
5764
- if (phonetic) {
5765
- visit(phonetic.phoneme.audioScriptId, id);
5766
- return;
5767
- }
5768
- for (const r of relations) if (r.entityId === id) visit(r.sourceId, phoneticScriptId);
5769
- };
5770
- visit(recordingId);
5771
- if (!found.size) {
5772
- for (const r of relations) if (r.sourceId === recordingId && snapshot["audio-script-entities"][r.entityId]) found.set(r.entityId, void 0);
5773
- }
5774
- return [...found].map(([audioScriptId, phoneticScriptId]) => phoneticScriptId === void 0 ? { audioScriptId } : {
5775
- audioScriptId,
5776
- phoneticScriptId
5777
- });
5778
- }
5779
- /** Every AudioScript in the document with its PhoneticScripts, the Speech Clips saying it and the Caption Clips showing it. */
5780
- function toAudioScriptViews(snapshot) {
5781
- const views = /* @__PURE__ */ new Map();
5782
- const segmentIndex = (scriptId, segmentId) => {
5783
- const index = snapshot["audio-script-entities"][scriptId]?.segments.findIndex((s) => s.id === segmentId) ?? -1;
5784
- return index < 0 ? void 0 : index;
5785
- };
5786
- for (const [id, script] of Object.entries(snapshot["audio-script-entities"])) views.set(id, {
5787
- id,
5788
- segments: script.segments.map((segment) => {
5789
- const rich = snapshot.richText[segment.id];
5790
- const language = rich ? markedLanguage(langsFromDelta(rich.delta)) : void 0;
5791
- return language === void 0 ? {
5792
- id: segment.id,
5793
- text: segment.text
5794
- } : {
5795
- id: segment.id,
5796
- text: segment.text,
5797
- language
5798
- };
5799
- }),
5800
- sourceMediaIds: [],
5801
- phoneticScripts: [],
5802
- speeches: [],
5803
- captions: []
5804
- });
5805
- for (const r of Object.values(snapshot["derived-from-relations"])) if (snapshot["media-entities"][r.sourceId]) views.get(r.entityId)?.sourceMediaIds.push(r.sourceId);
5806
- for (const [id, phonetic] of Object.entries(snapshot["phonetic-script-entities"])) {
5807
- const { audioScriptId, segmentId, phonemeScript } = phonetic.phoneme;
5808
- const { digest } = phonetic;
5809
- const segment = segmentIndex(audioScriptId, segmentId);
5810
- const text = snapshot.phoneticText[id]?.text;
5811
- views.get(audioScriptId)?.phoneticScripts.push({
5812
- id,
5813
- ...segment === void 0 ? {} : { segment },
5814
- ...text === void 0 ? {} : { text },
5815
- ...phonemeScript === void 0 ? {} : { phonemeScript },
5816
- ...digest === void 0 ? {} : { digest }
5817
- });
5818
- }
5819
- const timbres = Object.values(snapshot["voice-timbre-relations"]);
5820
- for (const track of resolveDslLayout(snapshot).tracks) for (const { clipId } of track.clips) {
5821
- const source = snapshot["clip-entities"][clipId]?.source;
5822
- if (!source) continue;
5823
- if (snapshot["media-entities"][source]?.kind === "voiceover-recording") {
5824
- const voices = timbres.filter((r) => r.recordingId === source).flatMap((r) => {
5825
- const voice = snapshot["voice-entities"][r.voiceId];
5826
- if (!voice) return [];
5827
- return [voice.name === void 0 ? {
5828
- voiceId: r.voiceId,
5829
- key: voice.key
5830
- } : {
5831
- voiceId: r.voiceId,
5832
- key: voice.key,
5833
- name: voice.name
5834
- }];
5835
- });
5836
- for (const spoken of spokenScripts(snapshot, source)) {
5837
- const applied = appliedSpeech(snapshot, source, spoken);
5838
- views.get(spoken.audioScriptId)?.speeches.push({
5839
- clipId,
5840
- recordingId: source,
5841
- ...spoken.phoneticScriptId === void 0 ? {} : { phoneticScriptId: spoken.phoneticScriptId },
5842
- voices,
5843
- ...applied === void 0 ? {} : { applied }
5844
- });
5845
- }
5846
- continue;
5847
- }
5848
- const caption = snapshot["caption-entities"][source];
5849
- if (!caption?.selection || caption.text !== void 0 || !snapshot.captionText[source]) continue;
5850
- const { audioScriptId, segmentId } = caption.selection;
5851
- const segment = segmentIndex(audioScriptId, segmentId);
5852
- if (segment !== void 0) views.get(audioScriptId)?.captions.push({
5853
- clipId,
5854
- captionId: source,
5855
- segment
5856
- });
5857
- }
5858
- return [...views.values()];
5859
- }
5860
- /**
5861
- * Whether a recording still matches what it was synthesized from: the digest its derived-from
5862
- * records against the source's file digest now. An AudioScript has no file, so a recording
5863
- * derived from a script directly is not judged.
5864
- */
5865
- function appliedSpeech(snapshot, recordingId, spoken) {
5866
- const sourceId = spoken.phoneticScriptId ?? spoken.audioScriptId;
5867
- const recorded = Object.values(snapshot["derived-from-relations"]).find((r) => r.entityId === recordingId && r.sourceId === sourceId)?.sourceDigest;
5868
- const current = spoken.phoneticScriptId === void 0 ? void 0 : snapshot["phonetic-script-entities"][sourceId]?.digest;
5869
- return recorded === void 0 || current === void 0 ? void 0 : recorded === current;
5870
- }
5871
- //#endregion
5872
8001
  //#region src/dsl/projection/caption-style.ts
5873
8002
  const fields = {
5874
8003
  fontSize: "font_size",
@@ -5905,6 +8034,9 @@ function fromDraftStyle(style) {
5905
8034
  };
5906
8035
  }
5907
8036
  //#endregion
8037
+ //#region src/dsl/projection/video-draft-types.ts
8038
+ const DEFAULT_UNIT_TIME_MS = 33.333;
8039
+ //#endregion
5908
8040
  //#region src/dsl/projection/to-video-draft.ts
5909
8041
  /** A content read view, not an archive of authoring identities, rich-text marks or provenance. */
5910
8042
  function toVideoDraft(snapshot) {
@@ -6392,4 +8524,4 @@ function importedScript(id, text, mintSegment) {
6392
8524
  };
6393
8525
  }
6394
8526
  //#endregion
6395
- export { DslEditor as a, DslProjectionError as c, createInitialMedeoDsl as i, toVideoDraft as n, MedeoDsl as o, toAudioScriptViews as r, resolveDslLayout as s, fromVideoDraft as t };
8527
+ export { defaultIdFactory as _, DslEditor as a, tupleHash as b, UnsupportedDocumentFormatError as c, medeoDslLoroShape as d, captionContentCodec as f, DslProjectionError as g, resolveDslLayout as h, createInitialMedeoDsl as i, assertDslDocument as l, timeAnchorCodec as m, toVideoDraft as n, toAudioScriptViews as o, isInvalidAtomic as p, DEFAULT_UNIT_TIME_MS as r, MedeoDsl as s, fromVideoDraft as t, documentFormat as u, relationId as v, resourceId as y };