@mengine/medeo-client 2.1.1-dsl.1 → 2.1.1-dsl.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,29 +21,22 @@ function resourceId(kind, system, key) {
21
21
  function relationId(table, value) {
22
22
  const v = value;
23
23
  switch (table) {
24
- case "clip-source-relations": return `cs:${v.clipId}`;
25
- case "time-anchor-relations": return `ta:${v.from}`;
26
- case "caption-content-relations": return `cc:${v.captionId}`;
27
- case "caption-alignment-relations": return `ca:${v.captionId}`;
28
24
  case "voice-timbre-relations": return `voice-timbre:${tupleHash([v.recordingId, v.voiceId])}`;
29
25
  case "derived-from-relations": return `derived-from:${tupleHash([v.entityId, v.sourceId])}`;
30
- case "from-asset-relations": return `from-asset:${v.audioScriptId}`;
31
- case "to-asset-relations": return `to-asset:${v.audioScriptId}`;
32
26
  }
33
27
  throw new Error(`Unknown relation table: ${table}`);
34
28
  }
35
29
  const defaultIdFactory = (kind) => `${kind}_${globalThis.crypto.randomUUID()}`;
36
30
  const resourceKinds = {
37
31
  "media-entities": "media",
38
- "voice-entities": "voice",
39
- "asset-entities": "asset"
32
+ "voice-entities": "voice"
40
33
  };
41
34
  /** A resource row's ID is derived from its locator, so one external resource is one entity. */
42
35
  function assertResourceIdentity(table, id, value) {
43
36
  const kind = resourceKinds[table];
44
37
  if (kind && id !== resourceId(kind, value.system, value.key)) throw new Error("Resource identity does not match locator");
45
38
  }
46
- /** A relation row's ID is derived from its uniqueness key. */
39
+ /** A relation row's ID is derived from its two ends. */
47
40
  function assertRelationIdentity(table, id, value) {
48
41
  if (id !== relationId(table, value)) throw new Error("Relation ID does not match endpoints");
49
42
  }
@@ -61,16 +54,19 @@ const optional$1 = (check) => ({
61
54
  check,
62
55
  optional: true
63
56
  });
57
+ const reservedIds = [
58
+ "$cid",
59
+ "__proto__",
60
+ "constructor",
61
+ "prototype"
62
+ ];
63
+ const id = (v) => nonempty(v) && !reservedIds.includes(v);
64
+ const cursor = (v) => v instanceof Cursor;
64
65
  function isRecord(value) {
65
66
  return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Cursor);
66
67
  }
67
68
  function assertId(value) {
68
- if (!nonempty(value) || [
69
- "$cid",
70
- "__proto__",
71
- "constructor",
72
- "prototype"
73
- ].includes(value)) throw new Error("Expected a nonempty, non-reserved ID");
69
+ if (!id(value)) throw new Error("Expected a nonempty, non-reserved ID");
74
70
  }
75
71
  function validLanguage(value) {
76
72
  if (typeof value !== "string") return false;
@@ -126,6 +122,39 @@ const seqMarkerFields = {
126
122
  function assertSeqMarker(value) {
127
123
  checkFields(value, seqMarkerFields);
128
124
  }
125
+ const timeAnchorFields = {
126
+ to: required(id),
127
+ offsetMs: required(integer),
128
+ fallback_abs_ms: required(nonnegative)
129
+ };
130
+ /** A time anchor's own fields; what it points at is checked by `assertReferenceAdmitted`. */
131
+ function assertTimeAnchor(value) {
132
+ checkFields(value, timeAnchorFields);
133
+ }
134
+ const selectionFields = {
135
+ audioScriptId: required(id),
136
+ segmentId: required(id),
137
+ start: optional$1(cursor),
138
+ end: optional$1(cursor)
139
+ };
140
+ /** A whole segment, or a run inside it: both ends or neither. */
141
+ const segmentSelection = (fields) => (v) => object(fields)(v) && v.start === void 0 === (v.end === void 0);
142
+ function assertCaptionContent(value) {
143
+ if (!segmentSelection(selectionFields)(value)) throw new Error("Invalid segment selection");
144
+ }
145
+ const phonemeFields = {
146
+ ...selectionFields,
147
+ phonemeScript: optional$1(string)
148
+ };
149
+ function assertPhoneme(value) {
150
+ if (!segmentSelection(phonemeFields)(value)) throw new Error("Invalid phoneme");
151
+ }
152
+ const segmentFields = {
153
+ id: required(id),
154
+ text: required(string)
155
+ };
156
+ /** A script's segments: each with its own id, unique within the script. */
157
+ const segments = (v) => Array.isArray(v) && v.every(object(segmentFields)) && new Set(v.map((segment) => segment.id)).size === v.length;
129
158
  const locator = {
130
159
  system: required(oneOf("memota", "memota-speech")),
131
160
  key: required(nonempty)
@@ -138,7 +167,9 @@ const entityFields = {
138
167
  },
139
168
  "clip-entities": {
140
169
  seqMarker: required(object(seqMarkerFields)),
141
- volume: optional$1(finite)
170
+ volume: optional$1(finite),
171
+ source: required(id),
172
+ anchor: optional$1(object(timeAnchorFields))
142
173
  },
143
174
  "media-entities": {
144
175
  ...locator,
@@ -148,10 +179,18 @@ const entityFields = {
148
179
  digest: optional$1(nonempty)
149
180
  },
150
181
  "audio-script-entities": {
151
- body: required(string),
182
+ segments: required(segments),
152
183
  defaultLanguage: optional$1(validLanguage)
153
184
  },
185
+ "phonetic-script-entities": {
186
+ phoneme: optional$1(segmentSelection(phonemeFields)),
187
+ system: optional$1(oneOf("memota")),
188
+ key: optional$1(nonempty),
189
+ storageKey: optional$1(nonempty),
190
+ digest: optional$1(nonempty)
191
+ },
154
192
  "caption-entities": {
193
+ selection: optional$1(segmentSelection(selectionFields)),
155
194
  text: optional$1(string),
156
195
  style: optional$1(object(styleFields))
157
196
  },
@@ -159,55 +198,49 @@ const entityFields = {
159
198
  system: required(oneOf("voice-library")),
160
199
  key: required(nonempty),
161
200
  name: optional$1(string)
162
- },
163
- "asset-entities": {
164
- ...locator,
165
- storageKey: optional$1(nonempty),
166
- digest: optional$1(nonempty)
167
201
  }
168
202
  };
169
203
  const entityTables = Object.keys(entityFields);
204
+ /**
205
+ * Fields stored as one encoded string: written whole, never merged field by field. A patch to one
206
+ * is merged into the current value first, then the whole value is written.
207
+ */
208
+ const atomicFields = {
209
+ "clip-entities": ["seqMarker", "anchor"],
210
+ "phonetic-script-entities": ["phoneme"],
211
+ "caption-entities": ["selection"]
212
+ };
170
213
  const relationFields = {
171
- "clip-source-relations": {
172
- clipId: required(nonempty),
173
- sourceId: required(nonempty)
174
- },
175
- "time-anchor-relations": {
176
- from: required(nonempty),
177
- to: required(nonempty),
178
- offsetMs: required(integer),
179
- fallback_abs_ms: required(nonnegative)
180
- },
181
- "caption-content-relations": {
182
- captionId: required(nonempty),
183
- audioScriptId: required(nonempty),
184
- start: required((v) => v instanceof Cursor),
185
- end: required((v) => v instanceof Cursor)
186
- },
187
- "caption-alignment-relations": {
188
- captionId: required(nonempty),
189
- mediaId: required(nonempty),
190
- startMs: required(nonnegative),
191
- endMs: required(nonnegative)
192
- },
193
214
  "voice-timbre-relations": {
194
- recordingId: required(nonempty),
195
- voiceId: required(nonempty)
215
+ recordingId: required(id),
216
+ voiceId: required(id)
196
217
  },
197
218
  "derived-from-relations": {
198
- entityId: required(nonempty),
199
- sourceId: required(nonempty)
200
- },
201
- "from-asset-relations": {
202
- audioScriptId: required(nonempty),
203
- assetId: required(nonempty)
204
- },
205
- "to-asset-relations": {
206
- audioScriptId: required(nonempty),
207
- assetId: required(nonempty)
219
+ entityId: required(id),
220
+ sourceId: required(id),
221
+ sourceDigest: optional$1(nonempty)
208
222
  }
209
223
  };
210
224
  const relationTables = Object.keys(relationFields);
225
+ const fileFields = [
226
+ "system",
227
+ "key",
228
+ "storageKey",
229
+ "digest"
230
+ ];
231
+ const phonemeScriptOf = (row) => isRecord(row.phoneme) ? row.phoneme.phonemeScript : void 0;
232
+ /**
233
+ * A PhoneticScript as a write leaves it: written for a segment (D181), and its phonemeScript is raw
234
+ * content stored as its file (D178) — with text the row names that file and its digest, without
235
+ * text it has no file, and rewritten text is a new file.
236
+ */
237
+ function assertPhoneticScript(before, after) {
238
+ if (!isRecord(after.phoneme)) throw new Error("A PhoneticScript is written for a segment of its base script");
239
+ if (phonemeScriptOf(after) === void 0) {
240
+ if (fileFields.some((field) => after[field] !== void 0)) throw new Error("A PhoneticScript without text has no file");
241
+ } 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");
242
+ 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");
243
+ }
211
244
  function assertEntity(table, value) {
212
245
  checkFields(value, entityFields[table]);
213
246
  if (table === "media-entities") {
@@ -219,15 +252,15 @@ function assertEntity(table, value) {
219
252
  /** Validate only touched fields, so an unrelated edit can proceed in a merged, invalid document. */
220
253
  function assertEntityPatch(table, patch, current) {
221
254
  if (!isRecord(patch)) throw new Error("Expected an entity patch");
222
- if (table === "audio-script-entities" && Object.hasOwn(patch, "body")) throw new Error("Edit body through the Text adapter");
255
+ if (table === "audio-script-entities" && Object.hasOwn(patch, "segments")) throw new Error("Change segments with segment mutations and edit their text through the Text adapter");
223
256
  if (table === "caption-entities" && current.style !== void 0 && Object.hasOwn(patch, "style") && patch.style === void 0) throw new Error("Reset individual style fields; retain the style Map");
224
257
  if (table === "caption-entities" && current.text !== void 0 && patch.text !== void 0) throw new Error("Edit Caption text through the Text adapter");
225
- const next = mergeFields(current, patch);
258
+ const next = patchRow(table, current, patch);
226
259
  for (const key of Object.keys(patch)) {
227
260
  const field = entityFields[table][key];
228
261
  if (!field || !field.optional && next[key] === void 0 || next[key] !== void 0 && !field.check(next[key])) throw new Error(`Invalid patch field: ${key}`);
229
262
  }
230
- if (table === "media-entities" || table === "voice-entities" || table === "asset-entities") {
263
+ if (table === "media-entities" || table === "voice-entities") {
231
264
  for (const key of [
232
265
  "system",
233
266
  "key",
@@ -243,18 +276,25 @@ function assertEntityPatch(table, patch, current) {
243
276
  }
244
277
  function assertRelation(table, value) {
245
278
  checkFields(value, relationFields[table]);
246
- for (const [key, endpoint] of Object.entries(value)) if (key.endsWith("Id") || key === "from" || key === "to") assertId(endpoint);
279
+ }
280
+ /**
281
+ * The row after a patch. An atomic field merges into its current value, so a partial patch keeps
282
+ * the rest of it; an unreadable stored value is replaced instead, so writing a whole value repairs it.
283
+ */
284
+ function patchRow(table, current, patch) {
285
+ const next = mergeFields(current, patch);
286
+ for (const key of atomicFields[table] ?? []) {
287
+ const old = current[key];
288
+ const value = patch[key];
289
+ if (value !== void 0 && isRecord(old) && old.invalid === true) next[key] = isRecord(value) ? mergeFields({}, value) : value;
290
+ }
291
+ return next;
247
292
  }
248
293
  /** Undefined deletes; nested patches retain sibling fields and an existing empty style Map. */
249
294
  function mergeFields(target, patch) {
250
295
  const result = { ...target };
251
296
  for (const [key, value] of Object.entries(patch)) {
252
- if ([
253
- "$cid",
254
- "__proto__",
255
- "constructor",
256
- "prototype"
257
- ].includes(key)) throw new Error(`Reserved field: ${key}`);
297
+ if (reservedIds.includes(key)) throw new Error(`Reserved field: ${key}`);
258
298
  if (value === void 0) delete result[key];
259
299
  else result[key] = isRecord(value) ? mergeFields(isRecord(result[key]) ? result[key] : {}, value) : value;
260
300
  }
@@ -1252,36 +1292,60 @@ function codec(encode, decode) {
1252
1292
  }
1253
1293
  };
1254
1294
  }
1295
+ /** A Clip's time anchor; the Clip holding it is the anchored end. */
1255
1296
  const timeAnchorCodec = codec((v) => {
1256
- assertRelation("time-anchor-relations", v);
1297
+ assertTimeAnchor(v);
1257
1298
  return JSON.stringify({
1258
- from: v.from,
1259
1299
  to: v.to,
1260
1300
  offsetMs: v.offsetMs,
1261
1301
  fallback_abs_ms: v.fallback_abs_ms
1262
1302
  });
1263
1303
  }, (raw) => {
1264
1304
  const v = JSON.parse(raw);
1265
- assertRelation("time-anchor-relations", v);
1305
+ assertTimeAnchor(v);
1266
1306
  return v;
1267
1307
  });
1308
+ /** A segment selection as stored: a run's Cursors as their native bytes in unpadded base64url. */
1309
+ function encodeSelection(v) {
1310
+ return {
1311
+ audioScriptId: v.audioScriptId,
1312
+ segmentId: v.segmentId,
1313
+ ...v.start === void 0 || v.end === void 0 ? {} : {
1314
+ start: bytesToBase64url(v.start.encode()),
1315
+ end: bytesToBase64url(v.end.encode())
1316
+ }
1317
+ };
1318
+ }
1319
+ function decodeSelection(v) {
1320
+ if (!v || typeof v !== "object") throw new Error("Expected a segment selection");
1321
+ const { start, end, ...rest } = v;
1322
+ if (start === void 0 && end === void 0) return rest;
1323
+ if (typeof start !== "string" || typeof end !== "string") throw new Error("Expected encoded Cursor pair");
1324
+ return {
1325
+ ...rest,
1326
+ start: Cursor.decode(base64urlToBytes(start)),
1327
+ end: Cursor.decode(base64urlToBytes(end))
1328
+ };
1329
+ }
1330
+ /** A Caption's selection. */
1268
1331
  const captionContentCodec = codec((v) => {
1269
- assertRelation("caption-content-relations", v);
1332
+ assertCaptionContent(v);
1333
+ return JSON.stringify(encodeSelection(v));
1334
+ }, (raw) => {
1335
+ const value = decodeSelection(JSON.parse(raw));
1336
+ assertCaptionContent(value);
1337
+ return value;
1338
+ });
1339
+ /** A PhoneticScript's selection and what to synthesize for it, stored as one string so they move together. */
1340
+ const phonemeCodec = codec((v) => {
1341
+ assertPhoneme(v);
1270
1342
  return JSON.stringify({
1271
- captionId: v.captionId,
1272
- audioScriptId: v.audioScriptId,
1273
- start: bytesToBase64url(v.start.encode()),
1274
- end: bytesToBase64url(v.end.encode())
1343
+ ...encodeSelection(v),
1344
+ ...v.phonemeScript === void 0 ? {} : { phonemeScript: v.phonemeScript }
1275
1345
  });
1276
1346
  }, (raw) => {
1277
- const v = JSON.parse(raw);
1278
- if (typeof v?.start !== "string" || typeof v?.end !== "string") throw new Error("Expected encoded Cursor pair");
1279
- const value = {
1280
- ...v,
1281
- start: Cursor.decode(base64urlToBytes(v.start)),
1282
- end: Cursor.decode(base64urlToBytes(v.end))
1283
- };
1284
- assertRelation("caption-content-relations", value);
1347
+ const value = decodeSelection(JSON.parse(raw));
1348
+ assertPhoneme(value);
1285
1349
  return value;
1286
1350
  });
1287
1351
  /** A Clip's sequence marker is stored as one string, so it is taken or replaced whole. */
@@ -1304,13 +1368,19 @@ const optional = { required: false };
1304
1368
  const mergeable = { mergeableMapChildContainers: true };
1305
1369
  const strings = (keys) => Object.fromEntries(keys.map((key) => [key, schema.String()]));
1306
1370
  const relation = (keys) => schema.LoroMapRecord(schema.LoroMap(strings(keys)), mergeable);
1307
- const atomicValue = (codec) => schema.String().transform({
1371
+ const transform = (codec) => ({
1308
1372
  ...codec,
1309
1373
  isEqual: "encoded-value-equality",
1310
1374
  validateEncodedType: true
1311
1375
  });
1312
- const atomic = (codec) => schema.LoroMapRecord(atomicValue(codec));
1313
- /** Only direct children inherit mergeable identity. Body and ordinary entity rows keep normal identities. */
1376
+ /** One field stored as one encoded string, so it is taken or replaced whole. */
1377
+ const atomicValue = (codec) => schema.String().transform(transform(codec));
1378
+ const optionalAtomicValue = (codec) => schema.String(optional).transform(transform(codec));
1379
+ /**
1380
+ * Only direct children inherit mergeable identity. Text and ordinary entity rows keep normal
1381
+ * identities, so deleting a row also drops what a peer wrote into it concurrently: a relation an
1382
+ * entity holds at most one of is a field of that row and never outlives it.
1383
+ */
1314
1384
  const medeoDslLoroShape = schema({
1315
1385
  "timeline-entities": schema.LoroMapRecord(schema.LoroMap({})),
1316
1386
  "track-entities": schema.LoroMapRecord(schema.LoroMap({
@@ -1319,7 +1389,9 @@ const medeoDslLoroShape = schema({
1319
1389
  })),
1320
1390
  "clip-entities": schema.LoroMapRecord(schema.LoroMap({
1321
1391
  seqMarker: atomicValue(seqMarkerCodec),
1322
- volume: schema.Number(optional)
1392
+ volume: schema.Number(optional),
1393
+ source: schema.String(),
1394
+ anchor: optionalAtomicValue(timeAnchorCodec)
1323
1395
  })),
1324
1396
  "media-entities": schema.LoroMapRecord(schema.LoroMap({
1325
1397
  kind: schema.String(),
@@ -1330,10 +1402,21 @@ const medeoDslLoroShape = schema({
1330
1402
  digest: schema.String(optional)
1331
1403
  }), mergeable),
1332
1404
  "audio-script-entities": schema.LoroMapRecord(schema.LoroMap({
1333
- body: schema.LoroText(),
1405
+ segments: schema.LoroMovableList(schema.LoroMap({
1406
+ id: schema.String(),
1407
+ text: schema.LoroText()
1408
+ }), (segment) => segment.id),
1334
1409
  defaultLanguage: schema.String(optional)
1335
1410
  })),
1411
+ "phonetic-script-entities": schema.LoroMapRecord(schema.LoroMap({
1412
+ phoneme: atomicValue(phonemeCodec),
1413
+ system: schema.String(optional),
1414
+ key: schema.String(optional),
1415
+ storageKey: schema.String(optional),
1416
+ digest: schema.String(optional)
1417
+ })),
1336
1418
  "caption-entities": schema.LoroMapRecord(schema.LoroMap({
1419
+ selection: optionalAtomicValue(captionContentCodec),
1337
1420
  text: schema.LoroText(optional),
1338
1421
  style: schema.LoroMap({
1339
1422
  font: schema.LoroMap({
@@ -1359,26 +1442,13 @@ const medeoDslLoroShape = schema({
1359
1442
  key: schema.String(),
1360
1443
  name: schema.String(optional)
1361
1444
  }), mergeable),
1362
- "asset-entities": schema.LoroMapRecord(schema.LoroMap({
1363
- system: schema.String(),
1364
- key: schema.String(),
1365
- storageKey: schema.String(optional),
1366
- digest: schema.String(optional)
1367
- }), mergeable),
1368
1445
  "contain-relations": schema.LoroTree(schema.LoroMap({ entityId: schema.String() })),
1369
- "clip-source-relations": relation(["clipId", "sourceId"]),
1370
- "time-anchor-relations": atomic(timeAnchorCodec),
1371
- "caption-content-relations": atomic(captionContentCodec),
1372
- "caption-alignment-relations": schema.LoroMapRecord(schema.LoroMap({
1373
- captionId: schema.String(),
1374
- mediaId: schema.String(),
1375
- startMs: schema.Number(),
1376
- endMs: schema.Number()
1377
- }), mergeable),
1378
1446
  "voice-timbre-relations": relation(["recordingId", "voiceId"]),
1379
- "derived-from-relations": relation(["entityId", "sourceId"]),
1380
- "from-asset-relations": relation(["audioScriptId", "assetId"]),
1381
- "to-asset-relations": relation(["audioScriptId", "assetId"])
1447
+ "derived-from-relations": schema.LoroMapRecord(schema.LoroMap({
1448
+ entityId: schema.String(),
1449
+ sourceId: schema.String(),
1450
+ sourceDigest: schema.String(optional)
1451
+ }), mergeable)
1382
1452
  });
1383
1453
  //#endregion
1384
1454
  //#region ../medeo-dsl/src/schema/document-format.ts
@@ -1407,13 +1477,10 @@ function assertDslDocument(doc) {
1407
1477
  }
1408
1478
  //#endregion
1409
1479
  //#region ../medeo-dsl/src/schema/text-styles.ts
1410
- /** How rich-text marks extend at their edges: a language runs on into new text, a pause stays on its space. */
1411
- const textStyles = {
1412
- language: { expand: "after" },
1413
- pauseMs: { expand: "none" }
1414
- };
1480
+ /** How rich-text marks extend at their edges: a language runs on into text typed after it. */
1481
+ const textStyles = { language: { expand: "after" } };
1415
1482
  //#endregion
1416
1483
  //#region src/dsl/projection/video-draft-types.ts
1417
1484
  const DEFAULT_UNIT_TIME_MS = 33.333;
1418
1485
  //#endregion
1419
- export { assertRelation as $, hardenCidDescriptors as A, safeStringify as B, applySchemaToInferOptions as C, deepEqual as D, decodeNestedJsonValues as E, isObject as F, valuesEqual as G, stripUndefined as H, isObjectLike as I, getChildSchema as J, CID_KEY as K, isStateAndSchemaOfType as L, inferContainerTypeFromValue as M, insertChildToMap as N, defineCidProperty as O, isArrayLike as P, assertId as Q, isTreeID as R, applyEncode as S, containerIdToContainerType as T, tryInferContainerType as U, schemaToContainerType as V, tryUpdateToContainer as W, assertEntity as X, getMapFieldSchema as Y, assertEntityPatch as Z, isLoroTreeSchema as _, documentFormat as a, assertRelationIdentity as at, validateSchema as b, isInvalidAtomic as c, relationId as ct, getDefaultValue as d, entityTables as et, isContainerSchema as f, isLoroMovableListSchema as g, isLoroMapSchema as h, assertDslDocument as i, validLanguage as it, hasTransform as j, getRootContainerByType as k, timeAnchorCodec as l, resourceId as lt, isLoroListSchema as m, textStyles as n, mergeFields as nt, medeoDslLoroShape as o, assertResourceIdentity as ot, isListLikeSchema as p, getChildContainerSchema as q, UnsupportedDocumentFormatError as r, relationTables as rt, captionContentCodec as s, defaultIdFactory as st, DEFAULT_UNIT_TIME_MS as t, isRecord as tt, schema as u, tupleHash as ut, isRootSchemaType as v, cidsEqual as w, applyDecode as x, schemaContainsIgnoreField as y, isValueOfContainerType as z };
1486
+ export { assertEntityPatch as $, getRootContainerByType as A, isValueOfContainerType as B, applyEncode as C, decodeNestedJsonValues as D, containerIdToContainerType as E, isArrayLike as F, tryUpdateToContainer as G, schemaToContainerType as H, isObject as I, getChildContainerSchema as J, valuesEqual as K, isObjectLike as L, hasTransform as M, inferContainerTypeFromValue as N, deepEqual as O, insertChildToMap as P, assertEntity as Q, isStateAndSchemaOfType as R, applyDecode as S, cidsEqual as T, stripUndefined as U, safeStringify as V, tryInferContainerType as W, getMapFieldSchema as X, getChildSchema as Y, assertCaptionContent as Z, isLoroMovableListSchema as _, tupleHash as _t, documentFormat as a, atomicFields as at, schemaContainsIgnoreField as b, isInvalidAtomic as c, mergeFields as ct, schema as d, validLanguage as dt, assertId as et, getDefaultValue as f, assertRelationIdentity as ft, isLoroMapSchema as g, resourceId as gt, isLoroListSchema as h, relationId as ht, assertDslDocument as i, assertTimeAnchor as it, hardenCidDescriptors as j, defineCidProperty as k, phonemeCodec as l, patchRow as lt, isListLikeSchema as m, defaultIdFactory as mt, textStyles as n, assertPhoneticScript as nt, medeoDslLoroShape as o, entityTables as ot, isContainerSchema as p, assertResourceIdentity as pt, CID_KEY as q, UnsupportedDocumentFormatError as r, assertRelation as rt, captionContentCodec as s, isRecord as st, DEFAULT_UNIT_TIME_MS as t, assertPhoneme as tt, timeAnchorCodec as u, relationTables as ut, isLoroTreeSchema as v, applySchemaToInferOptions as w, validateSchema as x, isRootSchemaType as y, isTreeID as z };