@sanity/agent-mutations 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1644 @@
1
+ import { isInternationalizedArrayField, isV5InternationalizedArray, createError, getValueAtPath, resolveFieldSchemaAtPath, validateValue, validateInternationalizedArraySet, validateDocumentLanguageField, validateInternationalizedArrayItems, validateUniqueItems } from "@sanity/agent-schema/validation";
2
+ import { resolveFieldSchema, isPrimitiveType } from "@sanity/agent-schema";
3
+ import { isPublishedId, isVersionId, isDraftId, getPublishedId } from "@sanity/id-utils";
4
+ function extractArrayPath(path) {
5
+ const arrayFields = [], currentPath = path;
6
+ let offset = 0;
7
+ for (; offset < currentPath.length; ) {
8
+ const selectorMatch = currentPath.slice(offset).match(/^([^.[]+)(\[_key==["'][^"']+["']\])/);
9
+ if (selectorMatch)
10
+ arrayFields.push(selectorMatch[1]), offset += selectorMatch[0].length, currentPath[offset] === "." && offset++;
11
+ else {
12
+ const remainingMatch = currentPath.slice(offset).match(/^([^.[]+)/);
13
+ remainingMatch && arrayFields.length > 0 && arrayFields.push(remainingMatch[1]);
14
+ break;
15
+ }
16
+ }
17
+ if (arrayFields.length > 0)
18
+ return arrayFields.join(".");
19
+ const firstFieldMatch = path.match(/^([^.[]+)/);
20
+ return firstFieldMatch ? firstFieldMatch[1] : path;
21
+ }
22
+ function groupOperationsByArrayContext(params) {
23
+ const groups = [];
24
+ if ((params.set && params.set.length > 0 || params.unset && params.unset.length > 0 || params.insertBefore && params.insertBefore.length > 0 || params.insertAfter && params.insertAfter.length > 0) && groups.push({
25
+ context: "main",
26
+ operations: {
27
+ set: params.set || [],
28
+ unset: params.unset || [],
29
+ append: [],
30
+ insertBefore: params.insertBefore || [],
31
+ insertAfter: params.insertAfter || []
32
+ }
33
+ }), params.append && params.append.length > 0) {
34
+ const appendsByArrayPath = /* @__PURE__ */ new Map();
35
+ for (const appendOp of params.append) {
36
+ const arrayPath = extractArrayPath(appendOp.path);
37
+ appendsByArrayPath.has(arrayPath) || appendsByArrayPath.set(arrayPath, []), appendsByArrayPath.get(arrayPath).push(appendOp);
38
+ }
39
+ for (const [arrayPath, appendOps] of appendsByArrayPath.entries())
40
+ if (appendOps.length > 1)
41
+ for (let i = 0; i < appendOps.length; i++)
42
+ groups.push({
43
+ context: `append:${arrayPath}:${i}`,
44
+ operations: {
45
+ set: [],
46
+ unset: [],
47
+ append: [appendOps[i]],
48
+ insertBefore: [],
49
+ insertAfter: []
50
+ }
51
+ });
52
+ else
53
+ groups.push({
54
+ context: `append:${arrayPath}`,
55
+ operations: {
56
+ set: [],
57
+ unset: [],
58
+ append: appendOps,
59
+ insertBefore: [],
60
+ insertAfter: []
61
+ }
62
+ });
63
+ }
64
+ return groups;
65
+ }
66
+ function buildPatchTransaction(options) {
67
+ const { client, documentId, operations, setIfMissing } = options, transaction = client.transaction(), groups = groupOperationsByArrayContext(operations);
68
+ for (const [path, value] of Object.entries(setIfMissing))
69
+ transaction.patch(documentId, { setIfMissing: { [path]: value } });
70
+ for (const group of groups) {
71
+ for (const op of group.operations.insertBefore) {
72
+ const path = `${op.arrayPath}[_key=="${op.key}"]`;
73
+ transaction.patch(documentId, { insert: { before: path, items: op.items } });
74
+ }
75
+ for (const op of group.operations.insertAfter) {
76
+ const path = `${op.arrayPath}[_key=="${op.key}"]`;
77
+ transaction.patch(documentId, { insert: { after: path, items: op.items } });
78
+ }
79
+ for (const op of group.operations.set)
80
+ op.value !== void 0 && transaction.patch(documentId, { set: { [op.path]: op.value } });
81
+ for (const path of group.operations.unset)
82
+ transaction.patch(documentId, { unset: [path] });
83
+ for (const op of group.operations.append)
84
+ transaction.patch(documentId, { insert: { after: op.path, items: op.items } });
85
+ }
86
+ return transaction;
87
+ }
88
+ const PRIMITIVE_TYPES = [
89
+ "string",
90
+ "number",
91
+ "boolean",
92
+ "date",
93
+ "datetime",
94
+ "text",
95
+ "url",
96
+ "email",
97
+ "slug"
98
+ ];
99
+ function isPrimitiveArray(field) {
100
+ return !field || field.type !== "array" || !field.of || field.of.length === 0 ? !1 : field.of.every((item) => {
101
+ const itemType = item.type || (typeof item == "string" ? item : "");
102
+ return !itemType || typeof itemType != "string" ? !1 : PRIMITIVE_TYPES.includes(itemType);
103
+ });
104
+ }
105
+ function hasNumericIndex(path) {
106
+ return /\[\d+\]/.test(path);
107
+ }
108
+ function parseArrayIndex(path) {
109
+ const match = path.match(/^(.*?)\[(\d+)\](.*)$/);
110
+ return match ? {
111
+ basePath: match[1],
112
+ index: parseInt(match[2], 10),
113
+ restPath: match[3]
114
+ } : null;
115
+ }
116
+ function getArrayAtPath(document, path) {
117
+ const parts = path.split(/\.(?![^[]*\])/);
118
+ let current = document;
119
+ for (const part of parts) {
120
+ const keyMatch = part.match(/^([^[]+)\[_key=="([^"]+)"\]$/);
121
+ if (keyMatch) {
122
+ const [, fieldName, keyValue] = keyMatch, currentObj = current;
123
+ if (!currentObj[fieldName] || !Array.isArray(currentObj[fieldName]) || (current = currentObj[fieldName].find((item) => item._key === keyValue), !current)) return null;
124
+ continue;
125
+ }
126
+ if (!current || typeof current != "object")
127
+ return null;
128
+ current = current[part];
129
+ }
130
+ return Array.isArray(current) ? current : null;
131
+ }
132
+ function getKeyAtIndex(array, index) {
133
+ if (index < 0 || index >= array.length)
134
+ return null;
135
+ const item = array[index];
136
+ if (!item || typeof item != "object")
137
+ return null;
138
+ const key = item._key;
139
+ return typeof key == "string" ? key : null;
140
+ }
141
+ const BUILT_IN_BLOCK_SCHEMA = {
142
+ name: "block",
143
+ type: "object",
144
+ fields: [
145
+ { name: "style", type: "string" },
146
+ { name: "children", type: "array", of: [{ type: "span" }] },
147
+ { name: "markDefs", type: "array", of: [{ type: "object" }] },
148
+ { name: "listItem", type: "string" },
149
+ { name: "level", type: "number" }
150
+ ]
151
+ }, BUILT_IN_SPAN_SCHEMA = {
152
+ name: "span",
153
+ type: "object",
154
+ fields: [
155
+ { name: "text", type: "string" },
156
+ { name: "marks", type: "array", of: [{ type: "string" }] }
157
+ ]
158
+ }, BUILT_IN_SCHEMAS = {
159
+ block: BUILT_IN_BLOCK_SCHEMA,
160
+ span: BUILT_IN_SPAN_SCHEMA
161
+ };
162
+ function getDocumentItemAtPath(document, pathParts, upToIndex) {
163
+ let current = document;
164
+ for (let i = 0; i <= upToIndex; i++) {
165
+ const part = pathParts[i];
166
+ if (current == null || typeof current != "object")
167
+ return null;
168
+ const keyMatch = part.match(/^([^[]+)\[_key=="([^"]+)"\]$/);
169
+ if (keyMatch) {
170
+ const [, fieldName, keyValue] = keyMatch, arr = current[fieldName];
171
+ if (!Array.isArray(arr)) return null;
172
+ current = arr.find((item) => item && typeof item == "object" ? item._key === keyValue : !1);
173
+ continue;
174
+ }
175
+ const indexMatch = part.match(/^([^[]+)\[(\d+)\]$/);
176
+ if (indexMatch) {
177
+ const [, fieldName, indexStr] = indexMatch, arr = current[fieldName];
178
+ if (!Array.isArray(arr)) return null;
179
+ const index = parseInt(indexStr, 10);
180
+ if (index < 0 || index >= arr.length) return null;
181
+ current = arr[index];
182
+ continue;
183
+ }
184
+ current = current[part];
185
+ }
186
+ return current;
187
+ }
188
+ function getFieldAtPath(path, typeSchema, allSchemas, document) {
189
+ const parts = path.split(/\.(?![^[]*\])/);
190
+ let currentSchema = typeSchema;
191
+ for (let i = 0; i < parts.length; i++) {
192
+ const part = parts[i], keyMatch = part.match(/^([^[]+)\[_key=="([^"]+)"\]$/), indexMatch = part.match(/^([^[]+)\[(\d+)\]$/), fieldName = keyMatch ? keyMatch[1] : indexMatch ? indexMatch[1] : part, field = currentSchema.fields?.find((f) => f.name === fieldName);
193
+ if (!field) return null;
194
+ if (i === parts.length - 1)
195
+ return field;
196
+ let resolvedField = field;
197
+ if (field.type !== "array" && field.type !== "object" && field.type !== "string" && field.type !== "number" && field.type !== "boolean") {
198
+ const aliasSchema = allSchemas.find((s) => s.name === field.type);
199
+ aliasSchema && aliasSchema.type === "array" && aliasSchema.of && (resolvedField = { ...field, type: "array", of: aliasSchema.of });
200
+ }
201
+ if (resolvedField.type === "array" && resolvedField.of && resolvedField.of.length > 0) {
202
+ let itemSchema;
203
+ if (document && (keyMatch || indexMatch)) {
204
+ const docItem = getDocumentItemAtPath(document, parts, i);
205
+ if (docItem && typeof docItem == "object" && "_type" in docItem) {
206
+ const actualType = docItem._type;
207
+ if (itemSchema = allSchemas.find((s) => s.name === actualType) || BUILT_IN_SCHEMAS[actualType], !itemSchema) {
208
+ for (const itemTypeRef of resolvedField.of)
209
+ if (typeof itemTypeRef == "object" && itemTypeRef.name === actualType) {
210
+ itemSchema = itemTypeRef;
211
+ break;
212
+ }
213
+ }
214
+ }
215
+ }
216
+ if (!itemSchema)
217
+ for (const itemTypeRef of resolvedField.of) {
218
+ const itemTypeName = typeof itemTypeRef == "string" ? itemTypeRef : itemTypeRef.type;
219
+ if (itemTypeName && (itemSchema = allSchemas.find((s) => s.name === itemTypeName) || BUILT_IN_SCHEMAS[itemTypeName], itemSchema))
220
+ break;
221
+ }
222
+ if (!itemSchema)
223
+ return null;
224
+ currentSchema = itemSchema;
225
+ } else if (resolvedField.type === "object" && resolvedField.fields)
226
+ currentSchema = resolvedField;
227
+ else
228
+ return null;
229
+ }
230
+ return null;
231
+ }
232
+ function convertArrayIndexOperations(operations, typeSchema, allSchemas, document) {
233
+ const primitiveArrayOps = /* @__PURE__ */ new Map(), passThroughSets = [], passThroughUnsets = [];
234
+ if (operations.set && operations.set.length > 0)
235
+ for (const op of operations.set) {
236
+ if (!hasNumericIndex(op.path)) {
237
+ passThroughSets.push(op);
238
+ continue;
239
+ }
240
+ const parsed = parseArrayIndex(op.path);
241
+ if (!parsed) {
242
+ passThroughSets.push(op);
243
+ continue;
244
+ }
245
+ const { basePath, index, restPath } = parsed, field = getFieldAtPath(basePath, typeSchema, allSchemas, document);
246
+ if (!field)
247
+ throw new Error(
248
+ `Field validation failed:
249
+ - ${op.path}: Field "${basePath}" does not exist in schema "${typeSchema.name}"
250
+
251
+ Please correct the invalid field paths and try again.`
252
+ );
253
+ if (field.type !== "array")
254
+ throw new Error(
255
+ `Field validation failed:
256
+ - ${op.path}: Field "${basePath}" is not an array (type: ${field.type})
257
+
258
+ Please correct the invalid field paths and try again.`
259
+ );
260
+ if (isPrimitiveArray(field)) {
261
+ if (restPath)
262
+ throw new Error(
263
+ `Field validation failed:
264
+ - ${op.path}: Cannot access nested path "${restPath}" on primitive array item at "${basePath}[${index}]"
265
+
266
+ Primitive arrays (strings, numbers, etc.) don't have nested fields.`
267
+ );
268
+ const group = primitiveArrayOps.get(basePath) || { sets: [], unsets: [] };
269
+ group.sets.push({ index, value: op.value }), primitiveArrayOps.set(basePath, group);
270
+ } else {
271
+ const converted = convertObjectArraySetOperation(
272
+ op,
273
+ basePath,
274
+ index,
275
+ restPath,
276
+ typeSchema,
277
+ allSchemas,
278
+ document
279
+ );
280
+ passThroughSets.push(...converted);
281
+ }
282
+ }
283
+ if (operations.unset && operations.unset.length > 0)
284
+ for (const path of operations.unset) {
285
+ if (!hasNumericIndex(path)) {
286
+ passThroughUnsets.push(path);
287
+ continue;
288
+ }
289
+ const parsed = parseArrayIndex(path);
290
+ if (!parsed) {
291
+ passThroughUnsets.push(path);
292
+ continue;
293
+ }
294
+ const { basePath, index, restPath } = parsed, field = getFieldAtPath(basePath, typeSchema, allSchemas, document);
295
+ if (!field)
296
+ throw new Error(
297
+ `Field validation failed:
298
+ - ${path}: Field "${basePath}" does not exist in schema "${typeSchema.name}"
299
+
300
+ Please correct the invalid field paths and try again.`
301
+ );
302
+ if (field.type !== "array")
303
+ throw new Error(
304
+ `Field validation failed:
305
+ - ${path}: Field "${basePath}" is not an array (type: ${field.type})
306
+
307
+ Please correct the invalid field paths and try again.`
308
+ );
309
+ if (isPrimitiveArray(field)) {
310
+ if (restPath)
311
+ throw new Error(
312
+ `Field validation failed:
313
+ - ${path}: Cannot access nested path "${restPath}" on primitive array item at "${basePath}[${index}]"
314
+
315
+ Primitive arrays (strings, numbers, etc.) don't have nested fields.`
316
+ );
317
+ const group = primitiveArrayOps.get(basePath) || { sets: [], unsets: [] };
318
+ group.unsets.push(index), primitiveArrayOps.set(basePath, group);
319
+ } else
320
+ throw new Error(
321
+ `Unsetting object array items by index is not supported. Path: ${path}
322
+
323
+ To remove an item from an object array, use the unset operation with _key notation: items[_key=="..."]`
324
+ );
325
+ }
326
+ const appendsToMerge = /* @__PURE__ */ new Map(), passThroughAppends = [];
327
+ if (operations.append)
328
+ for (const appendOp of operations.append)
329
+ if (primitiveArrayOps.has(appendOp.path)) {
330
+ const existingItems = appendsToMerge.get(appendOp.path) ?? [];
331
+ appendsToMerge.set(appendOp.path, [...existingItems, ...appendOp.items]);
332
+ } else
333
+ passThroughAppends.push(appendOp);
334
+ const mergedSets = mergePrimitiveArrayOperations(primitiveArrayOps, appendsToMerge, document), result = {}, allSets = [...passThroughSets, ...mergedSets];
335
+ return allSets.length > 0 && (result.set = allSets), passThroughUnsets.length > 0 && (result.unset = passThroughUnsets), passThroughAppends.length > 0 && (result.append = passThroughAppends), operations.insertBefore && operations.insertBefore.length > 0 && (result.insertBefore = operations.insertBefore), operations.insertAfter && operations.insertAfter.length > 0 && (result.insertAfter = operations.insertAfter), result;
336
+ }
337
+ function mergePrimitiveArrayOperations(primitiveArrayOps, appendsToMerge, document) {
338
+ const mergedSets = [];
339
+ for (const [basePath, ops] of primitiveArrayOps) {
340
+ const currentArray = getArrayAtPath(document, basePath);
341
+ if (!currentArray)
342
+ throw new Error(
343
+ `Field validation failed:
344
+ - ${basePath}: Array "${basePath}" not found in document or is empty
345
+
346
+ Please ensure the array exists before modifying items by index.`
347
+ );
348
+ const maxIndex = currentArray.length - 1;
349
+ for (const { index } of ops.sets)
350
+ if (index < 0 || index > maxIndex)
351
+ throw new Error(
352
+ `Field validation failed:
353
+ - ${basePath}[${index}]: Index ${index} is out of bounds for array "${basePath}" (length: ${currentArray.length})
354
+
355
+ Please use a valid index between 0 and ${maxIndex}.`
356
+ );
357
+ for (const index of ops.unsets)
358
+ if (index < 0 || index > maxIndex)
359
+ throw new Error(
360
+ `Field validation failed:
361
+ - ${basePath}[${index}]: Index ${index} is out of bounds for array "${basePath}" (length: ${currentArray.length})
362
+
363
+ Please use a valid index between 0 and ${maxIndex}.`
364
+ );
365
+ const newArray = [...currentArray];
366
+ for (const { index, value } of ops.sets)
367
+ newArray[index] = value;
368
+ const uniqueUnsets = [...new Set(ops.unsets)].sort((a, b) => b - a);
369
+ for (const index of uniqueUnsets)
370
+ newArray.splice(index, 1);
371
+ const itemsToAppend = appendsToMerge.get(basePath);
372
+ itemsToAppend && newArray.push(...itemsToAppend), mergedSets.push({ path: basePath, value: newArray });
373
+ }
374
+ return mergedSets;
375
+ }
376
+ function convertObjectArraySetOperation(op, basePath, index, restPath, typeSchema, allSchemas, document) {
377
+ const currentArray = getArrayAtPath(document, basePath);
378
+ if (!currentArray)
379
+ throw new Error(
380
+ `Field validation failed:
381
+ - ${op.path}: Array "${basePath}" not found in document or is empty
382
+
383
+ Please ensure the array exists before modifying items by index.`
384
+ );
385
+ if (index < 0 || index >= currentArray.length)
386
+ throw new Error(
387
+ `Field validation failed:
388
+ - ${op.path}: Index ${index} is out of bounds for array "${basePath}" (length: ${currentArray.length})
389
+
390
+ Please use a valid index between 0 and ${currentArray.length - 1}.`
391
+ );
392
+ const key = getKeyAtIndex(currentArray, index);
393
+ if (!key)
394
+ throw new Error(
395
+ `Field validation failed:
396
+ - ${op.path}: Array item at "${basePath}[${index}]" does not have a _key field
397
+
398
+ Object arrays require _key fields for addressing. Please ensure all array items have _key fields.`
399
+ );
400
+ const newPath = `${basePath}[_key=="${key}"]${restPath}`;
401
+ if (restPath && hasNumericIndex(restPath)) {
402
+ const nestedParsed = parseArrayIndex(newPath);
403
+ if (nestedParsed) {
404
+ const nestedField = getFieldAtPath(nestedParsed.basePath, typeSchema, allSchemas, document);
405
+ if (nestedField && nestedField.type === "array")
406
+ if (isPrimitiveArray(nestedField)) {
407
+ const nestedArray = getArrayAtPath(document, nestedParsed.basePath);
408
+ if (!nestedArray)
409
+ throw new Error(
410
+ `Field validation failed:
411
+ - ${op.path}: Array "${nestedParsed.basePath}" not found in document
412
+
413
+ Please ensure the array exists before modifying items by index.`
414
+ );
415
+ const newArray = [...nestedArray];
416
+ return newArray[nestedParsed.index] = op.value, [{ path: nestedParsed.basePath, value: newArray }];
417
+ } else
418
+ return convertObjectArraySetOperation(
419
+ { path: newPath, value: op.value },
420
+ nestedParsed.basePath,
421
+ nestedParsed.index,
422
+ nestedParsed.restPath,
423
+ typeSchema,
424
+ allSchemas,
425
+ document
426
+ );
427
+ }
428
+ }
429
+ return [
430
+ {
431
+ path: newPath,
432
+ value: op.value
433
+ }
434
+ ];
435
+ }
436
+ function filterInvalidArrayItems(ops, errors) {
437
+ const perItemErrors = [], structuralErrors = [];
438
+ for (const error of errors)
439
+ error.itemIndex !== void 0 && error.arrayPath !== void 0 ? perItemErrors.push(error) : structuralErrors.push(error);
440
+ if (structuralErrors.length > 0)
441
+ return { hasStructuralErrors: !0, skippedItems: [] };
442
+ if (perItemErrors.length === 0)
443
+ return { hasStructuralErrors: !1, skippedItems: [] };
444
+ const invalidByPath = /* @__PURE__ */ new Map();
445
+ for (const error of perItemErrors) {
446
+ const existing = invalidByPath.get(error.arrayPath) ?? /* @__PURE__ */ new Set();
447
+ existing.add(error.itemIndex), invalidByPath.set(error.arrayPath, existing);
448
+ }
449
+ const skippedItems = [], seen = /* @__PURE__ */ new Set();
450
+ for (const error of perItemErrors) {
451
+ const key = `${error.arrayPath}:${error.itemIndex}`;
452
+ seen.has(key) || (seen.add(key), skippedItems.push({
453
+ arrayPath: error.arrayPath,
454
+ index: error.itemIndex,
455
+ type: void 0,
456
+ // filled below from the actual item
457
+ reason: error.message
458
+ }));
459
+ }
460
+ const cleanedSet = ops.set?.map((op) => {
461
+ const invalidIndices = invalidByPath.get(op.path);
462
+ if (!invalidIndices || !Array.isArray(op.value)) return op;
463
+ for (const idx of invalidIndices) {
464
+ const item = op.value[idx], skipped = skippedItems.find((s) => s.arrayPath === op.path && s.index === idx);
465
+ skipped && item && (skipped.type = item._type);
466
+ }
467
+ const filtered = op.value.filter((_, idx) => !invalidIndices.has(idx));
468
+ return { ...op, value: filtered };
469
+ }), cleanedAppend = ops.append?.map((op) => {
470
+ const invalidIndices = invalidByPath.get(op.path);
471
+ if (!invalidIndices) return op;
472
+ for (const idx of invalidIndices) {
473
+ const item = op.items[idx], skipped = skippedItems.find((s) => s.arrayPath === op.path && s.index === idx);
474
+ skipped && item && (skipped.type = item._type);
475
+ }
476
+ const filtered = op.items.filter((_, idx) => !invalidIndices.has(idx));
477
+ return { ...op, items: filtered };
478
+ }), filterInsert = (insertOps) => insertOps?.map((op) => {
479
+ const invalidIndices = invalidByPath.get(op.arrayPath);
480
+ if (!invalidIndices) return op;
481
+ for (const idx of invalidIndices) {
482
+ const item = op.items[idx], skipped = skippedItems.find((s) => s.arrayPath === op.arrayPath && s.index === idx);
483
+ skipped && item && (skipped.type = item._type);
484
+ }
485
+ const filtered = op.items.filter((_, idx) => !invalidIndices.has(idx));
486
+ return { ...op, items: filtered };
487
+ });
488
+ return {
489
+ hasStructuralErrors: !1,
490
+ skippedItems,
491
+ set: cleanedSet,
492
+ append: cleanedAppend,
493
+ insertBefore: filterInsert(ops.insertBefore),
494
+ insertAfter: filterInsert(ops.insertAfter)
495
+ };
496
+ }
497
+ function formatPartialWriteError(skippedItems, totalItemsByPath) {
498
+ const lines = [], byPath = /* @__PURE__ */ new Map();
499
+ for (const item of skippedItems) {
500
+ const existing = byPath.get(item.arrayPath) ?? [];
501
+ existing.push(item), byPath.set(item.arrayPath, existing);
502
+ }
503
+ for (const [arrayPath, items] of byPath) {
504
+ const total = totalItemsByPath.get(arrayPath) ?? 0, written = total - items.length, details = items.map((s) => `${s.type ?? "unknown"} at index ${s.index} (${s.reason})`).join("; ");
505
+ lines.push(
506
+ `Partial write to "${arrayPath}": wrote ${written}/${total} items. Skipped ${items.length}: ${details}.`
507
+ );
508
+ }
509
+ return lines.push("Read the document and use insertAfter to add the missing items."), lines.join(`
510
+ `);
511
+ }
512
+ function generateKey() {
513
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
514
+ let key = "";
515
+ for (let i = 0; i < 12; i++)
516
+ key += chars.charAt(Math.floor(Math.random() * chars.length));
517
+ return key;
518
+ }
519
+ function addMissingKeys(value, options) {
520
+ if (value == null)
521
+ return value;
522
+ if (Array.isArray(value))
523
+ return value.map((item) => {
524
+ if (item && typeof item == "object" && !Array.isArray(item)) {
525
+ const obj = item, processedObj = {};
526
+ for (const [key, val] of Object.entries(obj))
527
+ processedObj[key] = addMissingKeys(val);
528
+ return processedObj._key ? processedObj : {
529
+ _key: generateKey(),
530
+ ...processedObj
531
+ };
532
+ }
533
+ return addMissingKeys(item);
534
+ });
535
+ if (typeof value == "object") {
536
+ const obj = value, result = {};
537
+ for (const [key, val] of Object.entries(obj))
538
+ result[key] = addMissingKeys(val);
539
+ return options?.ensureRootKey && !result._key ? {
540
+ _key: generateKey(),
541
+ ...result
542
+ } : result;
543
+ }
544
+ return value;
545
+ }
546
+ function collectKeys(value, currentPath, keys) {
547
+ if (value != null) {
548
+ if (Array.isArray(value))
549
+ value.forEach((item, index) => {
550
+ if (item && typeof item == "object" && !Array.isArray(item)) {
551
+ const obj = item, itemPath = currentPath ? `${currentPath}.${index}` : `${index}`;
552
+ if (typeof obj._key == "string") {
553
+ const existing = keys.get(obj._key) || [];
554
+ existing.push(itemPath), keys.set(obj._key, existing);
555
+ }
556
+ for (const [key, val] of Object.entries(obj))
557
+ key !== "_key" && collectKeys(val, `${itemPath}.${key}`, keys);
558
+ } else {
559
+ const itemPath = currentPath ? `${currentPath}.${index}` : `${index}`;
560
+ collectKeys(item, itemPath, keys);
561
+ }
562
+ });
563
+ else if (typeof value == "object") {
564
+ const obj = value;
565
+ for (const [key, val] of Object.entries(obj)) {
566
+ const nestedPath = currentPath ? `${currentPath}.${key}` : key;
567
+ collectKeys(val, nestedPath, keys);
568
+ }
569
+ }
570
+ }
571
+ }
572
+ function regenerateDuplicatesInternal(value, currentPath, duplicateKeys, seenKeys, keyMapping) {
573
+ if (value == null)
574
+ return value;
575
+ if (Array.isArray(value))
576
+ return value.map((item, index) => {
577
+ if (item && typeof item == "object" && !Array.isArray(item)) {
578
+ const obj = item, itemPath2 = currentPath ? `${currentPath}.${index}` : `${index}`, oldKey = obj._key;
579
+ let newKey = oldKey;
580
+ if (oldKey && duplicateKeys.has(oldKey))
581
+ if (seenKeys.has(oldKey)) {
582
+ newKey = generateKey();
583
+ const oldKeyPath = `${itemPath2.split(".").slice(0, -1).join(".")}[_key=="${oldKey}"]`.replace(/^\./, ""), newKeyPath = `${itemPath2.split(".").slice(0, -1).join(".")}[_key=="${newKey}"]`.replace(/^\./, "");
584
+ keyMapping.set(itemPath2, newKeyPath || `[_key=="${newKey}"]`), oldKeyPath && keyMapping.set(oldKeyPath, newKeyPath || `[_key=="${newKey}"]`);
585
+ } else
586
+ seenKeys.add(oldKey);
587
+ const processedObj = {};
588
+ for (const [key, val] of Object.entries(obj))
589
+ key !== "_key" && (processedObj[key] = regenerateDuplicatesInternal(
590
+ val,
591
+ `${itemPath2}.${key}`,
592
+ duplicateKeys,
593
+ seenKeys,
594
+ keyMapping
595
+ ));
596
+ return {
597
+ _key: newKey,
598
+ ...processedObj
599
+ };
600
+ }
601
+ const itemPath = currentPath ? `${currentPath}.${index}` : `${index}`;
602
+ return regenerateDuplicatesInternal(item, itemPath, duplicateKeys, seenKeys, keyMapping);
603
+ });
604
+ if (typeof value == "object") {
605
+ const obj = value, result = {};
606
+ for (const [key, val] of Object.entries(obj)) {
607
+ const nestedPath = currentPath ? `${currentPath}.${key}` : key;
608
+ result[key] = regenerateDuplicatesInternal(
609
+ val,
610
+ nestedPath,
611
+ duplicateKeys,
612
+ seenKeys,
613
+ keyMapping
614
+ );
615
+ }
616
+ return result;
617
+ }
618
+ return value;
619
+ }
620
+ function regenerateDuplicateKeys(value) {
621
+ const keyPaths = /* @__PURE__ */ new Map();
622
+ collectKeys(value, "", keyPaths);
623
+ const duplicateKeys = /* @__PURE__ */ new Set();
624
+ let duplicatesFound = 0;
625
+ for (const [key, paths] of keyPaths)
626
+ paths.length > 1 && (duplicateKeys.add(key), duplicatesFound += paths.length - 1);
627
+ if (duplicateKeys.size === 0)
628
+ return {
629
+ value,
630
+ keyMapping: /* @__PURE__ */ new Map(),
631
+ duplicatesFound: 0
632
+ };
633
+ const keyMapping = /* @__PURE__ */ new Map();
634
+ return {
635
+ value: regenerateDuplicatesInternal(
636
+ value,
637
+ "",
638
+ duplicateKeys,
639
+ /* @__PURE__ */ new Set(),
640
+ keyMapping
641
+ ),
642
+ keyMapping,
643
+ duplicatesFound
644
+ };
645
+ }
646
+ function normalizeKeyQuotes(path) {
647
+ return path.replace(/\[_key=='([^']+)'\]/g, '[_key=="$1"]');
648
+ }
649
+ function normalizeArrayIndices(path) {
650
+ return path.replace(/\[(\d+)\]/g, ".$1");
651
+ }
652
+ function applySingleTransformation(path, keyMapping) {
653
+ if (keyMapping.has(path))
654
+ return { path: keyMapping.get(path), transformed: !0 };
655
+ let longestMatch = "", longestMatchValue = "";
656
+ for (const [oldPath, newPath] of keyMapping.entries())
657
+ (path === oldPath || path.startsWith(`${oldPath}.`) || path.startsWith(`${oldPath}[`)) && oldPath.length > longestMatch.length && (longestMatch = oldPath, longestMatchValue = newPath);
658
+ if (longestMatch) {
659
+ const remainder = path.slice(longestMatch.length);
660
+ return { path: longestMatchValue + remainder, transformed: !0 };
661
+ }
662
+ return { path, transformed: !1 };
663
+ }
664
+ function transformPathWithKeyMapping(path, keyMapping) {
665
+ if (!keyMapping || keyMapping.size === 0)
666
+ return path;
667
+ let currentPath = normalizeArrayIndices(path), iterations = 0;
668
+ const maxIterations = 10;
669
+ for (; iterations < maxIterations; ) {
670
+ const result = applySingleTransformation(currentPath, keyMapping);
671
+ if (!result.transformed)
672
+ break;
673
+ currentPath = result.path, iterations++;
674
+ }
675
+ return currentPath;
676
+ }
677
+ function mapKeyThroughKeyMapping(key, keyMapping) {
678
+ return !keyMapping || typeof keyMapping != "object" ? key : keyMapping[key] ?? key;
679
+ }
680
+ function resolveTopLevelFieldSchema(path, typeSchema, allSchemas) {
681
+ const topField = path.split(".")[0].split("[")[0], field = typeSchema.fields?.find((f) => f.name === topField);
682
+ return field ? allSchemas.find((s) => s.name === field.type) ?? field : void 0;
683
+ }
684
+ function resolveLanguageIds(fieldSchema, allSchemas) {
685
+ let languages = fieldSchema.options?.languages;
686
+ return languages?.length || (languages = allSchemas.find((s) => s.name === fieldSchema.type)?.options?.languages), languages?.length ? new Set(languages.map((l) => l.id)) : /* @__PURE__ */ new Set();
687
+ }
688
+ function isV4PatternItem(item, languageIds) {
689
+ const key = item._key;
690
+ return typeof key == "string" && languageIds.has(key) && !("language" in item);
691
+ }
692
+ function isV5PatternItem(item) {
693
+ return "language" in item && typeof item.language == "string";
694
+ }
695
+ function normalizeItemV4ToV5(item) {
696
+ const languageCode = item._key;
697
+ return { ...item, _key: generateKey(), language: languageCode };
698
+ }
699
+ function normalizeItemV5ToV4(item) {
700
+ const { language: languageCode, ...rest } = item;
701
+ return { ...rest, _key: languageCode };
702
+ }
703
+ function normalizeItems(items, fieldSchema, allSchemas) {
704
+ const isV5 = isV5InternationalizedArray(fieldSchema, allSchemas), languageIds = resolveLanguageIds(fieldSchema, allSchemas);
705
+ return languageIds.size === 0 ? items : items.map((item) => {
706
+ if (typeof item != "object" || item === null || Array.isArray(item)) return item;
707
+ const obj = item;
708
+ if (isV5) {
709
+ if (isV4PatternItem(obj, languageIds))
710
+ return normalizeItemV4ToV5(obj);
711
+ } else if (isV5PatternItem(obj))
712
+ return normalizeItemV5ToV4(obj);
713
+ return item;
714
+ });
715
+ }
716
+ function normalizeInternationalizedArrays(operations, options) {
717
+ const { typeSchema, allSchemas } = options;
718
+ return {
719
+ set: operations.set?.map((op) => {
720
+ const fieldSchema = resolveTopLevelFieldSchema(op.path, typeSchema, allSchemas);
721
+ return !fieldSchema || !isInternationalizedArrayField(fieldSchema) || !Array.isArray(op.value) ? op : { ...op, value: normalizeItems(op.value, fieldSchema, allSchemas) };
722
+ }),
723
+ unset: operations.unset,
724
+ append: operations.append?.map((op) => {
725
+ const fieldSchema = resolveTopLevelFieldSchema(op.path, typeSchema, allSchemas);
726
+ return !fieldSchema || !isInternationalizedArrayField(fieldSchema) ? op : {
727
+ ...op,
728
+ items: normalizeItems(op.items, fieldSchema, allSchemas)
729
+ };
730
+ }),
731
+ insertBefore: operations.insertBefore?.map((op) => {
732
+ const fieldSchema = resolveTopLevelFieldSchema(op.arrayPath, typeSchema, allSchemas);
733
+ return !fieldSchema || !isInternationalizedArrayField(fieldSchema) ? op : { ...op, items: normalizeItems(op.items, fieldSchema, allSchemas) };
734
+ }),
735
+ insertAfter: operations.insertAfter?.map((op) => {
736
+ const fieldSchema = resolveTopLevelFieldSchema(op.arrayPath, typeSchema, allSchemas);
737
+ return !fieldSchema || !isInternationalizedArrayField(fieldSchema) ? op : { ...op, items: normalizeItems(op.items, fieldSchema, allSchemas) };
738
+ })
739
+ };
740
+ }
741
+ function isReferenceObject(value) {
742
+ return value !== null && typeof value == "object" && "_ref" in value && typeof value._ref == "string" && "_type" in value && typeof value._type == "string";
743
+ }
744
+ function getReferenceFieldDefinition(fieldPath, typeSchema, fullSchema) {
745
+ return resolveFieldSchema(fieldPath, typeSchema, fullSchema);
746
+ }
747
+ function getArrayItemSchema(arrayFieldPath, typeSchema, fullSchema) {
748
+ const field = getReferenceFieldDefinition(arrayFieldPath, typeSchema, fullSchema);
749
+ return !field || field.type !== "array" || !field.of || field.of.length === 0 || field.of.length > 1 ? null : field.of[0];
750
+ }
751
+ function isWeakReferenceField(fieldDefinition) {
752
+ return fieldDefinition.type === "reference" && fieldDefinition.weak === !0 ? !0 : fieldDefinition.type === "array" && fieldDefinition.of ? fieldDefinition.of.some((item) => item.type === "reference" && item.weak === !0) : !1;
753
+ }
754
+ const documentCache = /* @__PURE__ */ new Map();
755
+ function clearDocumentCache() {
756
+ documentCache.clear();
757
+ }
758
+ async function lookupDocument(client, docId) {
759
+ if (documentCache.has(docId))
760
+ return documentCache.get(docId);
761
+ try {
762
+ const doc = await client.getDocument(docId), result = doc ? { _type: doc._type } : null;
763
+ return documentCache.set(docId, result), result;
764
+ } catch {
765
+ return documentCache.set(docId, null), null;
766
+ }
767
+ }
768
+ async function normalizeReferenceObject(client, ref, fieldPath, typeSchema, fullSchema, targetDocumentId, validationErrors, applyStrengthenOnPublish, parentObjectType) {
769
+ let fieldDefinition;
770
+ if (typeSchema.type === "reference" ? fieldDefinition = typeSchema : fieldDefinition = getReferenceFieldDefinition(
771
+ fieldPath,
772
+ typeSchema,
773
+ fullSchema
774
+ ), !fieldDefinition && parentObjectType) {
775
+ const globalType = fullSchema.find((s) => s.name === parentObjectType);
776
+ if (globalType?.fields) {
777
+ const fieldName = fieldPath.split(".").pop()?.replace(/\[\d+\]$/, "");
778
+ if (fieldName) {
779
+ const field = globalType.fields.find((f) => f.name === fieldName);
780
+ field && (fieldDefinition = field);
781
+ }
782
+ }
783
+ }
784
+ if (fieldDefinition?.type === "array" && fieldDefinition.of) {
785
+ const referenceSchemas = fieldDefinition.of.filter((item) => item.type === "reference");
786
+ referenceSchemas.length === 1 && (fieldDefinition = referenceSchemas[0]);
787
+ }
788
+ const isSchemaWeak = fieldDefinition ? isWeakReferenceField(fieldDefinition) : !1, isTargetPublished = isPublishedId(targetDocumentId), originalRefId = ref._ref;
789
+ if (ref._type === "globalDocumentReference")
790
+ return { ...ref, _weak: !0 };
791
+ if (ref._weak) {
792
+ const publishedId2 = isVersionId(originalRefId) || isDraftId(originalRefId) ? getPublishedId(originalRefId) : originalRefId;
793
+ if (isSchemaWeak || ref._strengthenOnPublish)
794
+ return { ...ref, _ref: publishedId2 };
795
+ if (applyStrengthenOnPublish && !isTargetPublished) {
796
+ const allPossibleTypes2 = [];
797
+ fieldDefinition?.to && Array.isArray(fieldDefinition.to) && allPossibleTypes2.push(...fieldDefinition.to.map((t) => t.type).filter(Boolean));
798
+ const targetType = allPossibleTypes2.length === 1 ? allPossibleTypes2[0] : ref._type !== "reference" ? ref._type : allPossibleTypes2[0];
799
+ if (targetType)
800
+ return {
801
+ ...ref,
802
+ _ref: publishedId2,
803
+ _strengthenOnPublish: { type: targetType, template: { id: targetType } }
804
+ };
805
+ }
806
+ return { ...ref, _ref: publishedId2 };
807
+ }
808
+ let publishedId, needsWeakAndStrengthen = !1, documentType = null;
809
+ if (isVersionId(originalRefId)) {
810
+ if (isTargetPublished)
811
+ return validationErrors.push(
812
+ createError(
813
+ fieldPath,
814
+ "INVALID_REFERENCE",
815
+ "Cannot reference versioned document from published document",
816
+ `"${originalRefId}" (versioned)`,
817
+ "Published document reference",
818
+ "Use a published document ID instead of a versioned one"
819
+ )
820
+ ), null;
821
+ const versionedDoc = await lookupDocument(client, originalRefId);
822
+ if (!versionedDoc)
823
+ return validationErrors.push(
824
+ createError(
825
+ fieldPath,
826
+ "REFERENCE_NOT_FOUND",
827
+ "Referenced versioned document does not exist",
828
+ `"${originalRefId}"`,
829
+ "Valid document ID",
830
+ "Provide a document ID that exists in the dataset"
831
+ )
832
+ ), null;
833
+ documentType = versionedDoc._type, publishedId = getPublishedId(originalRefId), needsWeakAndStrengthen = !0;
834
+ } else if (isDraftId(originalRefId)) {
835
+ if (isTargetPublished)
836
+ return validationErrors.push(
837
+ createError(
838
+ fieldPath,
839
+ "INVALID_REFERENCE",
840
+ "Cannot reference draft document from published document",
841
+ `"${originalRefId}" (draft)`,
842
+ "Published document reference",
843
+ "Use a published document ID instead of a draft one"
844
+ )
845
+ ), null;
846
+ const draftDoc = await lookupDocument(client, originalRefId);
847
+ if (!draftDoc)
848
+ return validationErrors.push(
849
+ createError(
850
+ fieldPath,
851
+ "REFERENCE_NOT_FOUND",
852
+ "Referenced draft document does not exist",
853
+ `"${originalRefId}"`,
854
+ "Valid document ID",
855
+ "Provide a document ID that exists in the dataset"
856
+ )
857
+ ), null;
858
+ documentType = draftDoc._type, publishedId = getPublishedId(originalRefId), needsWeakAndStrengthen = !0;
859
+ } else {
860
+ publishedId = originalRefId;
861
+ const publishedDoc = await lookupDocument(client, publishedId);
862
+ if (!publishedDoc)
863
+ return validationErrors.push(
864
+ createError(
865
+ fieldPath,
866
+ "REFERENCE_NOT_FOUND",
867
+ "Referenced document does not exist",
868
+ `"${originalRefId}"`,
869
+ "Valid document ID",
870
+ "Provide a document ID that exists in the dataset"
871
+ )
872
+ ), null;
873
+ documentType = publishedDoc._type, needsWeakAndStrengthen = !1;
874
+ }
875
+ const normalized = {
876
+ ...ref
877
+ };
878
+ if (isSchemaWeak && (normalized._weak = !0), !applyStrengthenOnPublish)
879
+ return normalized;
880
+ const allPossibleTypes = [];
881
+ if (fieldDefinition?.to && Array.isArray(fieldDefinition.to) && allPossibleTypes.push(...fieldDefinition.to.map((t) => t.type).filter(Boolean)), allPossibleTypes.length > 0 && documentType && !allPossibleTypes.includes(documentType))
882
+ return validationErrors.push(
883
+ createError(
884
+ fieldPath,
885
+ "REFERENCE_WRONG_TYPE",
886
+ "Reference points to wrong document type",
887
+ `"${originalRefId}" (type: ${documentType})`,
888
+ `Reference to: ${allPossibleTypes.join(", ")}`,
889
+ `Change the reference to point to a document of type ${allPossibleTypes.join(" or ")}`
890
+ )
891
+ ), null;
892
+ if (!isSchemaWeak && needsWeakAndStrengthen && !isTargetPublished && documentType) {
893
+ let targetType = documentType;
894
+ allPossibleTypes.length === 1 && (targetType = allPossibleTypes[0]), normalized._ref = publishedId, normalized._weak = !0, normalized._strengthenOnPublish = {
895
+ type: targetType,
896
+ template: {
897
+ id: targetType
898
+ }
899
+ };
900
+ }
901
+ return normalized;
902
+ }
903
+ async function traverseAndNormalize(client, value, currentPath, typeSchema, fullSchema, targetDocumentId, validationErrors, applyStrengthenOnPublish, parentObjectType) {
904
+ if (value == null)
905
+ return value;
906
+ if (Array.isArray(value))
907
+ return (await Promise.all(
908
+ value.map(async (item, index) => {
909
+ const itemPath = `${currentPath}[${index}]`;
910
+ return await traverseAndNormalize(
911
+ client,
912
+ item,
913
+ itemPath,
914
+ typeSchema,
915
+ fullSchema,
916
+ targetDocumentId,
917
+ validationErrors,
918
+ applyStrengthenOnPublish,
919
+ parentObjectType
920
+ );
921
+ })
922
+ )).filter((item) => item !== null);
923
+ if (isReferenceObject(value))
924
+ return await normalizeReferenceObject(
925
+ client,
926
+ value,
927
+ currentPath,
928
+ typeSchema,
929
+ fullSchema,
930
+ targetDocumentId,
931
+ validationErrors,
932
+ applyStrengthenOnPublish,
933
+ parentObjectType
934
+ );
935
+ if (typeof value == "object") {
936
+ const obj = value, normalized = {}, thisObjectType = typeof obj._type == "string" ? obj._type : void 0;
937
+ for (const [key, val] of Object.entries(obj)) {
938
+ if (key.startsWith("_")) {
939
+ normalized[key] = val;
940
+ continue;
941
+ }
942
+ const fieldPath = currentPath ? `${currentPath}.${key}` : key, result = await traverseAndNormalize(
943
+ client,
944
+ val,
945
+ fieldPath,
946
+ typeSchema,
947
+ fullSchema,
948
+ targetDocumentId,
949
+ validationErrors,
950
+ applyStrengthenOnPublish,
951
+ thisObjectType
952
+ );
953
+ result !== null && (normalized[key] = result);
954
+ }
955
+ return normalized;
956
+ }
957
+ return value;
958
+ }
959
+ async function normalizeDocumentReferences(client, document, schema, applyStrengthenOnPublish = !0) {
960
+ if (clearDocumentCache(), !document || !schema || schema.length === 0)
961
+ return {
962
+ normalized: document,
963
+ validationErrors: []
964
+ };
965
+ const typeSchema = schema.find((t) => t.name === document._type);
966
+ if (!typeSchema)
967
+ return {
968
+ normalized: document,
969
+ validationErrors: []
970
+ };
971
+ const validationErrors = [];
972
+ return {
973
+ normalized: await traverseAndNormalize(
974
+ client,
975
+ document,
976
+ "",
977
+ typeSchema,
978
+ schema,
979
+ document._id,
980
+ validationErrors,
981
+ applyStrengthenOnPublish
982
+ ),
983
+ validationErrors
984
+ };
985
+ }
986
+ function getLastItemKey(arrayValue, excludeKeys) {
987
+ if (!(!Array.isArray(arrayValue) || arrayValue.length === 0))
988
+ for (let i = arrayValue.length - 1; i >= 0; i--) {
989
+ const item = arrayValue[i];
990
+ if (item && typeof item == "object" && "_key" in item) {
991
+ const key = item._key;
992
+ if (!excludeKeys || !excludeKeys.has(key))
993
+ return key;
994
+ }
995
+ }
996
+ }
997
+ function extractUnsetKeysForArray(unsetPaths, arrayPath) {
998
+ const keys = /* @__PURE__ */ new Set(), regex = new RegExp(`^${escapeRegex(arrayPath)}\\[_key==["']([^"']+)["']\\]$`);
999
+ for (const path of unsetPaths) {
1000
+ const match = path.match(regex);
1001
+ match && keys.add(match[1]);
1002
+ }
1003
+ return keys;
1004
+ }
1005
+ function escapeRegex(str) {
1006
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1007
+ }
1008
+ function collectExistingKeys(arrayValue) {
1009
+ const keys = /* @__PURE__ */ new Set();
1010
+ if (!Array.isArray(arrayValue)) return keys;
1011
+ for (const item of arrayValue)
1012
+ if (item && typeof item == "object" && "_key" in item) {
1013
+ const key = item._key;
1014
+ typeof key == "string" && keys.add(key);
1015
+ }
1016
+ return keys;
1017
+ }
1018
+ async function normalizeArrayItems(client, items, arrayPath, typeSchema, fullSchema, targetDocumentId, validationErrors, applyStrengthenOnPublish) {
1019
+ const arrayItemSchema = getArrayItemSchema(arrayPath, typeSchema, fullSchema), arrayFieldDef = getReferenceFieldDefinition(arrayPath, typeSchema, fullSchema), normalizedItems = [];
1020
+ for (const item of items) {
1021
+ let schemaForItem = arrayItemSchema;
1022
+ if (!schemaForItem && arrayFieldDef?.of) {
1023
+ const itemRecord = item;
1024
+ if (typeof itemRecord._ref == "string") {
1025
+ const matchingRefSchema = arrayFieldDef.of.find((s) => s.type !== "reference" ? !1 : s.name === itemRecord._type || s.type === itemRecord._type && !s.name);
1026
+ if (matchingRefSchema)
1027
+ schemaForItem = matchingRefSchema;
1028
+ else {
1029
+ const refSchemas = arrayFieldDef.of.filter((s) => s.type === "reference");
1030
+ if (refSchemas.length > 0) {
1031
+ const allWeak = refSchemas.every((s) => s.weak === !0), allStrong = refSchemas.every((s) => s.weak !== !0);
1032
+ if (allWeak || allStrong)
1033
+ schemaForItem = refSchemas[0];
1034
+ else {
1035
+ normalizedItems.push(item);
1036
+ continue;
1037
+ }
1038
+ }
1039
+ }
1040
+ } else
1041
+ schemaForItem = arrayFieldDef.of.find((ofSchema) => ofSchema.name === itemRecord._type || ofSchema.type === itemRecord._type) || null;
1042
+ }
1043
+ const normalizedItem = await traverseAndNormalize(
1044
+ client,
1045
+ item,
1046
+ "",
1047
+ schemaForItem || typeSchema,
1048
+ fullSchema,
1049
+ targetDocumentId,
1050
+ validationErrors,
1051
+ applyStrengthenOnPublish
1052
+ );
1053
+ normalizedItem !== null && normalizedItems.push(normalizedItem);
1054
+ }
1055
+ return normalizedItems;
1056
+ }
1057
+ function collectAllKeys(value, keys) {
1058
+ if (value != null) {
1059
+ if (Array.isArray(value))
1060
+ for (const item of value)
1061
+ if (item && typeof item == "object" && !Array.isArray(item)) {
1062
+ const obj = item;
1063
+ if (typeof obj._key == "string") {
1064
+ const count = keys.get(obj._key) || 0;
1065
+ keys.set(obj._key, count + 1);
1066
+ }
1067
+ for (const val of Object.values(obj))
1068
+ collectAllKeys(val, keys);
1069
+ } else
1070
+ collectAllKeys(item, keys);
1071
+ else if (typeof value == "object")
1072
+ for (const val of Object.values(value))
1073
+ collectAllKeys(val, keys);
1074
+ }
1075
+ }
1076
+ function regenerateDuplicateKeysInValue(value, duplicateKeys, conflictingKeys, seenKeys) {
1077
+ if (value == null) return value;
1078
+ if (Array.isArray(value))
1079
+ return value.map((item) => {
1080
+ if (item && typeof item == "object" && !Array.isArray(item)) {
1081
+ const obj = item, oldKey = obj._key;
1082
+ let newKey = oldKey;
1083
+ oldKey && (conflictingKeys.has(oldKey) || duplicateKeys.has(oldKey) && seenKeys.has(oldKey) ? newKey = generateKey() : seenKeys.add(oldKey));
1084
+ const processedObj = {};
1085
+ for (const [key, val] of Object.entries(obj))
1086
+ key !== "_key" && (processedObj[key] = regenerateDuplicateKeysInValue(
1087
+ val,
1088
+ duplicateKeys,
1089
+ conflictingKeys,
1090
+ seenKeys
1091
+ ));
1092
+ return { _key: newKey, ...processedObj };
1093
+ }
1094
+ return regenerateDuplicateKeysInValue(item, duplicateKeys, conflictingKeys, seenKeys);
1095
+ });
1096
+ if (typeof value == "object") {
1097
+ const obj = value, result = {};
1098
+ for (const [key, val] of Object.entries(obj))
1099
+ result[key] = regenerateDuplicateKeysInValue(val, duplicateKeys, conflictingKeys, seenKeys);
1100
+ return result;
1101
+ }
1102
+ return value;
1103
+ }
1104
+ function getParentPaths(path) {
1105
+ const parentPaths = [], arrayMatch = path.match(/\[_key==[^\]]+\]|\[\d+\]/);
1106
+ let pathToAnalyze;
1107
+ arrayMatch && arrayMatch.index !== void 0 ? pathToAnalyze = path.slice(0, arrayMatch.index) : pathToAnalyze = path;
1108
+ const segments = pathToAnalyze.split(".").filter(Boolean);
1109
+ for (let i = 0; i < segments.length - 1; i++)
1110
+ parentPaths.push(segments.slice(0, i + 1).join("."));
1111
+ return parentPaths;
1112
+ }
1113
+ function computeSetIfMissing(paths, typeSchema, fullSchema) {
1114
+ const setIfMissing = {};
1115
+ for (const path of paths) {
1116
+ const parentPaths = getParentPaths(path);
1117
+ for (const parentPath of parentPaths) {
1118
+ if (setIfMissing[parentPath] !== void 0) continue;
1119
+ const fieldSchema = resolveFieldSchema(parentPath, typeSchema, fullSchema);
1120
+ fieldSchema && (fieldSchema.type === "array" ? setIfMissing[parentPath] = [] : (fieldSchema.type === "object" || fieldSchema.fields) && (setIfMissing[parentPath] = fieldSchema.name ? { _type: fieldSchema.name } : {}));
1121
+ }
1122
+ }
1123
+ return setIfMissing;
1124
+ }
1125
+ function regenerateDuplicateKeysForAppend(items, existingArrayKeys) {
1126
+ const keyCounts = /* @__PURE__ */ new Map();
1127
+ collectAllKeys(items, keyCounts);
1128
+ const duplicateKeys = /* @__PURE__ */ new Set();
1129
+ for (const [key, count] of keyCounts)
1130
+ count > 1 && duplicateKeys.add(key);
1131
+ return duplicateKeys.size === 0 && existingArrayKeys.size === 0 ? items : regenerateDuplicateKeysInValue(
1132
+ items,
1133
+ duplicateKeys,
1134
+ existingArrayKeys,
1135
+ /* @__PURE__ */ new Set()
1136
+ );
1137
+ }
1138
+ async function normalizePatchOperations(client, operations, documentType, fullSchema, targetDocumentId, options = {}) {
1139
+ const { applyStrengthenOnPublish = !0, existingDocument } = options;
1140
+ if (clearDocumentCache(), !operations || !documentType || !fullSchema || fullSchema.length === 0)
1141
+ return {
1142
+ normalized: operations,
1143
+ validationErrors: [],
1144
+ setIfMissing: {}
1145
+ };
1146
+ const typeSchema = fullSchema.find((t) => t.name === documentType);
1147
+ if (!typeSchema)
1148
+ return {
1149
+ normalized: operations,
1150
+ validationErrors: [],
1151
+ setIfMissing: {}
1152
+ };
1153
+ const validationErrors = [], normalized = {};
1154
+ for (const [opType, opValue] of Object.entries(operations))
1155
+ if (opType === "set" && Array.isArray(opValue)) {
1156
+ const normalizedSet = [];
1157
+ for (const op of opValue) {
1158
+ const normalizedValue = await traverseAndNormalize(
1159
+ client,
1160
+ op.value,
1161
+ op.path,
1162
+ typeSchema,
1163
+ fullSchema,
1164
+ targetDocumentId,
1165
+ validationErrors,
1166
+ applyStrengthenOnPublish
1167
+ );
1168
+ normalizedValue !== null && normalizedSet.push({
1169
+ path: op.path,
1170
+ value: normalizedValue
1171
+ });
1172
+ }
1173
+ normalized[opType] = normalizedSet;
1174
+ } else if (opType === "append" && Array.isArray(opValue)) {
1175
+ const normalizedAppend = [], appendAfterKeyForPath = {};
1176
+ for (const op of opValue) {
1177
+ const normalizedItems = Array.isArray(op.items) ? await normalizeArrayItems(
1178
+ client,
1179
+ op.items,
1180
+ op.path,
1181
+ typeSchema,
1182
+ fullSchema,
1183
+ targetDocumentId,
1184
+ validationErrors,
1185
+ applyStrengthenOnPublish
1186
+ ) : [];
1187
+ if (normalizedItems.length > 0) {
1188
+ let resolvedPath = op.path, existingArrayKeys = /* @__PURE__ */ new Set();
1189
+ if (existingDocument) {
1190
+ const arrayValue = getValueAtPath(existingDocument, op.path);
1191
+ existingArrayKeys = collectExistingKeys(arrayValue);
1192
+ const unsetKeys = extractUnsetKeysForArray(operations.unset || [], op.path);
1193
+ let appendAfterKey = appendAfterKeyForPath[op.path];
1194
+ appendAfterKey || (appendAfterKey = getLastItemKey(arrayValue, unsetKeys)), appendAfterKey && (resolvedPath = `${op.path}[_key=="${appendAfterKey}"]`);
1195
+ }
1196
+ const deduplicatedItems = regenerateDuplicateKeysForAppend(
1197
+ normalizedItems,
1198
+ existingArrayKeys
1199
+ ), lastItem = deduplicatedItems[deduplicatedItems.length - 1];
1200
+ lastItem && typeof lastItem == "object" && "_key" in lastItem && (appendAfterKeyForPath[op.path] = lastItem._key), normalizedAppend.push({
1201
+ path: resolvedPath,
1202
+ items: deduplicatedItems
1203
+ });
1204
+ }
1205
+ }
1206
+ normalized[opType] = normalizedAppend;
1207
+ } else if ((opType === "insertBefore" || opType === "insertAfter") && Array.isArray(opValue)) {
1208
+ const normalizedInserts = [];
1209
+ for (const op of opValue) {
1210
+ const normalizedItems = Array.isArray(op.items) ? await normalizeArrayItems(
1211
+ client,
1212
+ op.items,
1213
+ op.arrayPath,
1214
+ typeSchema,
1215
+ fullSchema,
1216
+ targetDocumentId,
1217
+ validationErrors,
1218
+ applyStrengthenOnPublish
1219
+ ) : [];
1220
+ if (normalizedItems.length > 0) {
1221
+ let existingArrayKeys = /* @__PURE__ */ new Set();
1222
+ if (existingDocument) {
1223
+ const arrayValue = getValueAtPath(existingDocument, op.arrayPath);
1224
+ existingArrayKeys = collectExistingKeys(arrayValue);
1225
+ }
1226
+ const deduplicatedItems = regenerateDuplicateKeysForAppend(
1227
+ normalizedItems,
1228
+ existingArrayKeys
1229
+ );
1230
+ normalizedInserts.push({
1231
+ arrayPath: op.arrayPath,
1232
+ key: op.key,
1233
+ items: deduplicatedItems
1234
+ });
1235
+ }
1236
+ }
1237
+ normalized[opType] = normalizedInserts;
1238
+ } else
1239
+ normalized[opType] = opValue;
1240
+ const allPaths = [];
1241
+ if (normalized.set && Array.isArray(normalized.set))
1242
+ for (const op of normalized.set)
1243
+ allPaths.push(op.path);
1244
+ if (normalized.append && Array.isArray(normalized.append))
1245
+ for (const op of normalized.append)
1246
+ allPaths.push(op.path);
1247
+ const setIfMissing = computeSetIfMissing(allPaths, typeSchema, fullSchema);
1248
+ return {
1249
+ normalized,
1250
+ validationErrors,
1251
+ setIfMissing
1252
+ };
1253
+ }
1254
+ function acceptsFlatPortableText(fieldPath, typeSchema, allSchemas) {
1255
+ const fieldSchema = resolveFieldSchema(fieldPath, typeSchema, allSchemas);
1256
+ return fieldSchema ? arrayAcceptsBlocks(fieldSchema, allSchemas) : !1;
1257
+ }
1258
+ function acceptsOnlyFlatPortableText(fieldPath, typeSchema, allSchemas) {
1259
+ const fieldSchema = resolveFieldSchema(fieldPath, typeSchema, allSchemas);
1260
+ return fieldSchema ? arrayIsBlockOnly(fieldSchema, allSchemas) : !1;
1261
+ }
1262
+ function hasAnyFlatPortableTextField(typeSchema, allSchemas) {
1263
+ return typeSchema.fields ? typeSchema.fields.some((field) => {
1264
+ const resolved = field.type ? allSchemas.find((s) => s.name === field.type) ?? field : field;
1265
+ return arrayAcceptsBlocks(resolved, allSchemas);
1266
+ }) : !1;
1267
+ }
1268
+ function arrayAcceptsBlocks(fieldSchema, allSchemas) {
1269
+ let schema = fieldSchema;
1270
+ if (!schema.of && schema.type) {
1271
+ const resolved = allSchemas.find((s) => s.name === schema.type);
1272
+ resolved && (schema = resolved);
1273
+ }
1274
+ const arrayOf = schema.of;
1275
+ return !arrayOf || arrayOf.length === 0 ? !1 : arrayOf.some((item) => resolveBlockMember(item, allSchemas) !== void 0);
1276
+ }
1277
+ function arrayIsBlockOnly(fieldSchema, allSchemas) {
1278
+ let schema = fieldSchema;
1279
+ if (!schema.of && schema.type) {
1280
+ const resolved = allSchemas.find((s) => s.name === schema.type);
1281
+ resolved && (schema = resolved);
1282
+ }
1283
+ const arrayOf = schema.of;
1284
+ return !arrayOf || arrayOf.length === 0 ? !1 : arrayOf.every((item) => {
1285
+ const block = resolveBlockMember(item, allSchemas);
1286
+ if (!block) return !1;
1287
+ const annotations = block.marks?.annotations;
1288
+ return !annotations || annotations.length === 0;
1289
+ });
1290
+ }
1291
+ function resolveBlockMember(item, allSchemas) {
1292
+ if (item.type === "block") return item;
1293
+ if (item.type) {
1294
+ const resolved = allSchemas.find((s) => s.name === item.type);
1295
+ if (resolved?.type === "block") return resolved;
1296
+ }
1297
+ }
1298
+ function normalizeOperationPaths(operations) {
1299
+ return {
1300
+ set: operations.set?.map((op) => ({
1301
+ ...op,
1302
+ path: normalizeKeyQuotes(op.path)
1303
+ })),
1304
+ unset: operations.unset?.map((path) => normalizeKeyQuotes(path)),
1305
+ append: operations.append?.map((op) => ({
1306
+ ...op,
1307
+ path: normalizeKeyQuotes(op.path)
1308
+ })),
1309
+ insertBefore: operations.insertBefore?.map((op) => ({
1310
+ ...op,
1311
+ arrayPath: normalizeKeyQuotes(op.arrayPath)
1312
+ })),
1313
+ insertAfter: operations.insertAfter?.map((op) => ({
1314
+ ...op,
1315
+ arrayPath: normalizeKeyQuotes(op.arrayPath)
1316
+ }))
1317
+ };
1318
+ }
1319
+ function applyKeyMapping(operations, keyMapping) {
1320
+ return {
1321
+ set: operations.set?.map((op) => ({
1322
+ ...op,
1323
+ path: transformPathWithKeyMapping(op.path, keyMapping)
1324
+ })),
1325
+ unset: operations.unset?.map((path) => transformPathWithKeyMapping(path, keyMapping)),
1326
+ append: operations.append?.map((op) => ({
1327
+ ...op,
1328
+ path: transformPathWithKeyMapping(op.path, keyMapping)
1329
+ })),
1330
+ insertBefore: operations.insertBefore?.map((op) => ({
1331
+ ...op,
1332
+ arrayPath: transformPathWithKeyMapping(op.arrayPath, keyMapping),
1333
+ key: mapKeyThroughKeyMapping(op.key, keyMapping)
1334
+ })),
1335
+ insertAfter: operations.insertAfter?.map((op) => ({
1336
+ ...op,
1337
+ arrayPath: transformPathWithKeyMapping(op.arrayPath, keyMapping),
1338
+ key: mapKeyThroughKeyMapping(op.key, keyMapping)
1339
+ }))
1340
+ };
1341
+ }
1342
+ function addMissingKeysToOperations(operations) {
1343
+ return {
1344
+ set: operations.set?.map((op) => ({
1345
+ ...op,
1346
+ value: addMissingKeys(op.value)
1347
+ })),
1348
+ unset: operations.unset,
1349
+ append: operations.append?.map((op) => ({
1350
+ ...op,
1351
+ items: op.items.map((item) => addMissingKeys(item, { ensureRootKey: !0 }))
1352
+ })),
1353
+ insertBefore: operations.insertBefore?.map((op) => ({
1354
+ ...op,
1355
+ items: op.items.map((item) => addMissingKeys(item, { ensureRootKey: !0 }))
1356
+ })),
1357
+ insertAfter: operations.insertAfter?.map((op) => ({
1358
+ ...op,
1359
+ items: op.items.map((item) => addMissingKeys(item, { ensureRootKey: !0 }))
1360
+ }))
1361
+ };
1362
+ }
1363
+ function convertAppendToSetForMissingArrays(operations, document) {
1364
+ if (!operations.append || operations.append.length === 0)
1365
+ return operations;
1366
+ const remainingAppends = [], convertedSets = [];
1367
+ for (const op of operations.append) {
1368
+ const isSimplePath = !op.path.includes("["), existingValue = getValueAtPath(document, op.path), isMissingOrEmpty = existingValue == null || Array.isArray(existingValue) && existingValue.length === 0;
1369
+ isSimplePath && isMissingOrEmpty ? convertedSets.push({ path: op.path, value: [...op.items] }) : remainingAppends.push(op);
1370
+ }
1371
+ return convertedSets.length === 0 ? operations : {
1372
+ ...operations,
1373
+ set: [...operations.set ?? [], ...convertedSets],
1374
+ append: remainingAppends.length > 0 ? remainingAppends : void 0
1375
+ };
1376
+ }
1377
+ function prepareOperations(operations, options) {
1378
+ let prepared = normalizeOperationPaths(operations);
1379
+ return options.keyMapping && (prepared = applyKeyMapping(prepared, options.keyMapping)), prepared = convertArrayIndexOperations(
1380
+ prepared,
1381
+ options.typeSchema,
1382
+ options.allSchemas,
1383
+ options.document
1384
+ ), prepared = convertAppendToSetForMissingArrays(prepared, options.document), prepared = normalizeInternationalizedArrays(prepared, {
1385
+ typeSchema: options.typeSchema,
1386
+ allSchemas: options.allSchemas
1387
+ }), prepared = addMissingKeysToOperations(prepared), prepared;
1388
+ }
1389
+ function pathEndsWithArrayIndex(path) {
1390
+ return /\[\d+\]$/.test(path) || /\[_key==[^\]]+\]$/.test(path);
1391
+ }
1392
+ function resolveToArraySchema(fieldSchema, allSchemas) {
1393
+ if (fieldSchema.type === "array")
1394
+ return fieldSchema;
1395
+ if (fieldSchema.type && !isPrimitiveType(fieldSchema.type)) {
1396
+ const referencedSchema = allSchemas.find((s) => s.name === fieldSchema.type);
1397
+ if (referencedSchema)
1398
+ return referencedSchema;
1399
+ }
1400
+ return fieldSchema;
1401
+ }
1402
+ function getSchemaForSetValue(fieldSchema, path, value, allSchemas) {
1403
+ if (!pathEndsWithArrayIndex(path))
1404
+ return fieldSchema;
1405
+ const resolvedSchema = resolveToArraySchema(fieldSchema, allSchemas);
1406
+ if (resolvedSchema.type !== "array" || !resolvedSchema.of?.length)
1407
+ return fieldSchema;
1408
+ const itemSchemas = resolvedSchema.of;
1409
+ if (typeof value == "object" && value !== null && !Array.isArray(value)) {
1410
+ const valueType = value._type;
1411
+ if (valueType) {
1412
+ let matchingSchema = itemSchemas.find(
1413
+ (schema) => schema.name === valueType || schema.type === valueType
1414
+ );
1415
+ if (matchingSchema || (matchingSchema = allSchemas.find((s) => s.name === valueType)), matchingSchema)
1416
+ return matchingSchema;
1417
+ }
1418
+ }
1419
+ return itemSchemas[0];
1420
+ }
1421
+ function hasUniqueConstraint(fieldSchema) {
1422
+ return !!fieldSchema.validation?.some(
1423
+ (group) => group.rules.some((rule) => {
1424
+ const r = rule, ruleType = r.type || r.flag;
1425
+ return ruleType === "unique" || ruleType === "uniqueItems";
1426
+ })
1427
+ );
1428
+ }
1429
+ async function validatePatchOperations(operations, documentType, schema, context) {
1430
+ const errors = [], warnings = [], typeSchema = schema.find((s) => s.name === documentType);
1431
+ return typeSchema ? (await validateSetOperations(operations.set, typeSchema, schema, context, errors, warnings), validateUnsetOperations(operations.unset, typeSchema, schema, context, errors), await validateAppendOperations(operations.append, typeSchema, schema, context, errors, warnings), await validateInsertOperations(operations, typeSchema, schema, context, errors, warnings), {
1432
+ valid: errors.length === 0,
1433
+ errors,
1434
+ warnings
1435
+ }) : (errors.push(
1436
+ createError(
1437
+ "_type",
1438
+ "FIELD_NOT_IN_SCHEMA",
1439
+ `Document type "${documentType}" not found in schema`,
1440
+ documentType,
1441
+ "Valid document type",
1442
+ "Check the schema for valid document type names"
1443
+ )
1444
+ ), { valid: !1, errors, warnings });
1445
+ }
1446
+ async function validateSetOperations(ops, typeSchema, schema, context, errors, warnings) {
1447
+ if (ops)
1448
+ for (const op of ops) {
1449
+ const fieldSchema = resolveFieldSchemaAtPath(
1450
+ op.path,
1451
+ typeSchema,
1452
+ schema,
1453
+ context.existingDocument
1454
+ ).schema;
1455
+ if (!fieldSchema) {
1456
+ errors.push(
1457
+ createError(
1458
+ op.path,
1459
+ "FIELD_NOT_IN_SCHEMA",
1460
+ "Path does not exist in schema",
1461
+ op.path,
1462
+ "Valid field path",
1463
+ "Check the schema for valid field paths"
1464
+ )
1465
+ );
1466
+ continue;
1467
+ }
1468
+ if (op.value !== void 0) {
1469
+ const valueSchema = getSchemaForSetValue(fieldSchema, op.path, op.value, schema);
1470
+ await validateValue(op.value, valueSchema, op.path, errors, context, schema, warnings);
1471
+ }
1472
+ if (validateInternationalizedArraySet(op.path, op.value, fieldSchema, typeSchema, schema, errors), context.localizationConfig?.documentLevel) {
1473
+ const { languageField, availableLanguages } = context.localizationConfig.documentLevel;
1474
+ languageField && op.path === languageField && availableLanguages && validateDocumentLanguageField(op.value, languageField, availableLanguages, op.path, errors);
1475
+ }
1476
+ }
1477
+ }
1478
+ function validateUnsetOperations(ops, typeSchema, schema, context, errors) {
1479
+ if (ops)
1480
+ for (const path of ops)
1481
+ resolveFieldSchemaAtPath(path, typeSchema, schema, context.existingDocument).schema || errors.push(
1482
+ createError(
1483
+ path,
1484
+ "FIELD_NOT_IN_SCHEMA",
1485
+ "Path does not exist in schema",
1486
+ path,
1487
+ "Valid field path",
1488
+ "Check the schema for valid field paths"
1489
+ )
1490
+ );
1491
+ }
1492
+ async function validateAppendOperations(ops, typeSchema, schema, context, errors, warnings) {
1493
+ if (ops)
1494
+ for (const op of ops) {
1495
+ const fieldSchema = resolveFieldSchema(op.path, typeSchema, schema);
1496
+ if (!fieldSchema) {
1497
+ errors.push(
1498
+ createError(
1499
+ op.path,
1500
+ "FIELD_NOT_IN_SCHEMA",
1501
+ "Path does not exist in schema",
1502
+ op.path,
1503
+ "Valid array field path",
1504
+ "Check the schema for valid array field paths"
1505
+ )
1506
+ );
1507
+ continue;
1508
+ }
1509
+ if (context.existingDocument && op.path.includes("[_key==") && getValueAtPath(context.existingDocument, op.path) === void 0) {
1510
+ errors.push(
1511
+ createError(
1512
+ op.path,
1513
+ "FIELD_NOT_IN_SCHEMA",
1514
+ "Path does not exist in document",
1515
+ op.path,
1516
+ "Valid array path that exists in document",
1517
+ "Check that the path with _key selectors points to an existing location"
1518
+ )
1519
+ );
1520
+ continue;
1521
+ }
1522
+ const arraySchema = resolveToArraySchema(fieldSchema, schema);
1523
+ if (arraySchema.of && arraySchema.of.length > 0) {
1524
+ const errorCountBefore = errors.length;
1525
+ await validateValue(op.items, arraySchema, op.path, errors, context, schema, warnings);
1526
+ for (let e = errorCountBefore; e < errors.length; e++)
1527
+ errors[e].path = errors[e].path.replace(
1528
+ new RegExp(`^${op.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\[(\\d+)\\]`),
1529
+ `${op.path}[append:$1]`
1530
+ );
1531
+ }
1532
+ if (isInternationalizedArrayField(fieldSchema) && validateInternationalizedArrayItems(op.items, fieldSchema, schema, op.path, errors), hasUniqueConstraint(fieldSchema) && context.existingDocument) {
1533
+ const existingArray = getValueAtPath(context.existingDocument, op.path);
1534
+ Array.isArray(existingArray) && validateUniqueItems(op.items, existingArray, `${op.path}[append:`, errors);
1535
+ }
1536
+ }
1537
+ }
1538
+ async function validateInsertOperations(operations, typeSchema, schema, context, errors, warnings) {
1539
+ for (const opType of ["insertBefore", "insertAfter"]) {
1540
+ const insertOps = operations[opType];
1541
+ if (insertOps)
1542
+ for (const op of insertOps) {
1543
+ const fieldSchema = resolveFieldSchema(op.arrayPath, typeSchema, schema);
1544
+ if (!fieldSchema) {
1545
+ errors.push(
1546
+ createError(
1547
+ op.arrayPath,
1548
+ "FIELD_NOT_IN_SCHEMA",
1549
+ "Array path does not exist in schema",
1550
+ op.arrayPath,
1551
+ "Valid array field path",
1552
+ "Check the schema for valid array field paths"
1553
+ )
1554
+ );
1555
+ continue;
1556
+ }
1557
+ const resolvedSchema = resolveToArraySchema(fieldSchema, schema);
1558
+ if (resolvedSchema.type !== "array" && !resolvedSchema.of) {
1559
+ errors.push(
1560
+ createError(
1561
+ op.arrayPath,
1562
+ "TYPE_MISMATCH",
1563
+ "Path must point to an array field",
1564
+ fieldSchema.type || "unknown",
1565
+ "Array field",
1566
+ "Use an array field path for insert operations"
1567
+ )
1568
+ );
1569
+ continue;
1570
+ }
1571
+ const arraySchema = resolvedSchema;
1572
+ if (context.existingDocument) {
1573
+ const existingArray = getValueAtPath(context.existingDocument, op.arrayPath);
1574
+ Array.isArray(existingArray) && (existingArray.some(
1575
+ (item) => typeof item == "object" && item !== null && item._key === op.key
1576
+ ) || errors.push(
1577
+ createError(
1578
+ `${op.arrayPath}[_key=="${op.key}"]`,
1579
+ "INVALID_PATH",
1580
+ `Anchor key "${op.key}" not found in array`,
1581
+ op.key,
1582
+ "Existing _key in the array",
1583
+ "Use a _key that exists in the target array"
1584
+ )
1585
+ ));
1586
+ }
1587
+ if (isInternationalizedArrayField(fieldSchema) && validateInternationalizedArrayItems(op.items, fieldSchema, schema, op.arrayPath, errors), await validateInsertItems(op, opType, arraySchema, schema, context, errors, warnings), hasUniqueConstraint(fieldSchema) && context.existingDocument) {
1588
+ const existingArray = getValueAtPath(context.existingDocument, op.arrayPath);
1589
+ Array.isArray(existingArray) && validateUniqueItems(op.items, existingArray, `${op.arrayPath}[${opType}:`, errors);
1590
+ }
1591
+ }
1592
+ }
1593
+ }
1594
+ async function validateInsertItems(op, opType, arraySchema, schema, context, errors, warnings) {
1595
+ const itemSchemas = arraySchema.of || [];
1596
+ if (itemSchemas.length !== 0)
1597
+ for (let i = 0; i < op.items.length; i++) {
1598
+ const item = op.items[i], itemPath = `${op.arrayPath}[${opType}:${i}]`, errorCountBefore = errors.length, itemType = (typeof item == "object" && item !== null ? item : null)?._type;
1599
+ let matchingSchema;
1600
+ for (const ofSchema of itemSchemas) {
1601
+ if (ofSchema.name === itemType || ofSchema.type === itemType) {
1602
+ matchingSchema = ofSchema;
1603
+ break;
1604
+ }
1605
+ if (!itemType && isPrimitiveType(ofSchema.type)) {
1606
+ matchingSchema = ofSchema;
1607
+ break;
1608
+ }
1609
+ }
1610
+ matchingSchema && await validateValue(item, matchingSchema, itemPath, errors, context, schema, warnings);
1611
+ for (let e = errorCountBefore; e < errors.length; e++)
1612
+ errors[e].itemIndex = i, errors[e].arrayPath = op.arrayPath;
1613
+ }
1614
+ }
1615
+ export {
1616
+ acceptsFlatPortableText,
1617
+ acceptsOnlyFlatPortableText,
1618
+ addMissingKeys,
1619
+ buildPatchTransaction,
1620
+ clearDocumentCache,
1621
+ convertArrayIndexOperations,
1622
+ filterInvalidArrayItems,
1623
+ formatPartialWriteError,
1624
+ generateKey,
1625
+ getArrayAtPath,
1626
+ getArrayItemSchema,
1627
+ getKeyAtIndex,
1628
+ getReferenceFieldDefinition,
1629
+ hasAnyFlatPortableTextField,
1630
+ hasNumericIndex,
1631
+ isPrimitiveArray,
1632
+ mapKeyThroughKeyMapping,
1633
+ normalizeDocumentReferences,
1634
+ normalizeInternationalizedArrays,
1635
+ normalizeKeyQuotes,
1636
+ normalizePatchOperations,
1637
+ parseArrayIndex,
1638
+ prepareOperations,
1639
+ regenerateDuplicateKeys,
1640
+ transformPathWithKeyMapping,
1641
+ traverseAndNormalize,
1642
+ validatePatchOperations
1643
+ };
1644
+ //# sourceMappingURL=index.js.map