gt-sanity 2.0.15 → 2.0.17

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.
Files changed (48) hide show
  1. package/dist/index.cjs +157 -89
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +45 -29
  4. package/dist/index.d.ts +45 -29
  5. package/dist/index.js +157 -89
  6. package/dist/index.js.map +1 -1
  7. package/package.json +2 -2
  8. package/src/adapter/core.ts +8 -7
  9. package/src/adapter/types.ts +1 -1
  10. package/src/components/TranslationsProvider.tsx +42 -18
  11. package/src/configuration/baseDocumentLevelConfig/documentLevelPatch.test.ts +10 -2
  12. package/src/configuration/baseDocumentLevelConfig/documentLevelPatch.ts +17 -6
  13. package/src/configuration/baseDocumentLevelConfig/helpers/createI18nDocAndPatchMetadata.ts +1 -1
  14. package/src/configuration/baseDocumentLevelConfig/helpers/patchI18nDoc.test.ts +2 -1
  15. package/src/configuration/baseDocumentLevelConfig/helpers/patchI18nDoc.ts +3 -3
  16. package/src/hooks/useSecrets.ts +1 -1
  17. package/src/index.ts +3 -2
  18. package/src/sanity-api/resolveRefs.ts +21 -10
  19. package/src/serialization/BaseDocumentMerger.ts +56 -32
  20. package/src/serialization/BaseSerializationConfig.ts +30 -11
  21. package/src/serialization/__tests__/BaseDocumentDeserializer/baseDeserialization.test.ts +75 -69
  22. package/src/serialization/__tests__/BaseDocumentDeserializer/documentLevelDeserialization.test.ts +10 -14
  23. package/src/serialization/__tests__/BaseDocumentDeserializer/fieldLevelDeserialization.test.ts +10 -14
  24. package/src/serialization/__tests__/BaseDocumentMerger/baseMerge.test.ts +5 -9
  25. package/src/serialization/__tests__/BaseDocumentMerger/documentLevelMerge.test.ts +17 -19
  26. package/src/serialization/__tests__/BaseDocumentMerger/fieldLevelMerge.test.ts +33 -26
  27. package/src/serialization/__tests__/BaseDocumentMerger/utils.ts +20 -23
  28. package/src/serialization/__tests__/BaseDocumentSerializer/baseSerialization.test.ts +23 -23
  29. package/src/serialization/__tests__/BaseDocumentSerializer/documentLevelSerialization.test.ts +6 -6
  30. package/src/serialization/__tests__/BaseDocumentSerializer/fieldLevelSerialization.test.ts +8 -8
  31. package/src/serialization/__tests__/BaseDocumentSerializer/utils.ts +12 -10
  32. package/src/serialization/__tests__/__fixtures__/inlineSchema.ts +4 -1
  33. package/src/serialization/__tests__/__fixtures__/schema.ts +15 -6
  34. package/src/serialization/__tests__/global.setup.ts +7 -3
  35. package/src/serialization/__tests__/helpers.ts +11 -11
  36. package/src/serialization/data.ts +3 -3
  37. package/src/serialization/deserialize/BaseDocumentDeserializer.ts +41 -29
  38. package/src/serialization/index.ts +6 -1
  39. package/src/serialization/serialize/fieldFilters.ts +52 -30
  40. package/src/serialization/serialize/index.ts +48 -21
  41. package/src/serialization/types.ts +32 -17
  42. package/src/types.ts +1 -1
  43. package/src/utils/__tests__/documentIds.test.ts +2 -1
  44. package/src/utils/__tests__/forEachMatchingField.test.ts +1 -1
  45. package/src/utils/applyDocuments.ts +16 -14
  46. package/src/utils/batchProcessor.ts +21 -18
  47. package/src/utils/importUtils.ts +16 -10
  48. package/src/utils/serialize.ts +2 -1
package/dist/index.cjs CHANGED
@@ -43,7 +43,7 @@ class GTConfig {
43
43
  additionalDeserializers;
44
44
  additionalBlockDeserializers;
45
45
  static instance;
46
- constructor(secretsNamespace, languageField, sourceLocale, locales, singletons, singletonMapping, ignoreFields, dedupeFields, skipFields, translateDocuments, additionalStopTypes = [], additionalSerializers = {}, additionalDeserializers = {}, additionalBlockDeserializers = []) {
46
+ constructor(secretsNamespace, languageField, sourceLocale, locales, singletons, singletonMapping, ignoreFields, dedupeFields, skipFields, translateDocuments, additionalStopTypes = [], additionalSerializers = {}, additionalDeserializers = { types: {} }, additionalBlockDeserializers = []) {
47
47
  this.secretsNamespace = secretsNamespace, this.languageField = languageField, this.sourceLocale = sourceLocale, this.locales = locales, this.singletons = singletons, this.singletonMapping = singletonMapping, this.ignoreFields = ignoreFields, this.dedupeFields = dedupeFields, this.skipFields = skipFields, this.translateDocuments = translateDocuments, this.additionalStopTypes = additionalStopTypes, this.additionalSerializers = additionalSerializers, this.additionalDeserializers = additionalDeserializers, this.additionalBlockDeserializers = additionalBlockDeserializers;
48
48
  }
49
49
  static getInstance() {
@@ -59,12 +59,12 @@ class GTConfig {
59
59
  [],
60
60
  [],
61
61
  [],
62
- {},
62
+ { types: {} },
63
63
  {},
64
64
  []
65
65
  )), this.instance;
66
66
  }
67
- init(secretsNamespace, languageField, sourceLocale, locales, singletons, singletonMapping, ignoreFields, dedupeFields, skipFields, translateDocuments, additionalStopTypes = [], additionalSerializers = {}, additionalDeserializers = {}, additionalBlockDeserializers = []) {
67
+ init(secretsNamespace, languageField, sourceLocale, locales, singletons, singletonMapping, ignoreFields, dedupeFields, skipFields, translateDocuments, additionalStopTypes = [], additionalSerializers = {}, additionalDeserializers = { types: {} }, additionalBlockDeserializers = []) {
68
68
  this.secretsNamespace = secretsNamespace, this.languageField = languageField, this.sourceLocale = sourceLocale, this.locales = locales, this.singletons = singletons, this.singletonMapping = singletonMapping, this.ignoreFields = ignoreFields, this.dedupeFields = dedupeFields, this.skipFields = skipFields, this.translateDocuments = translateDocuments, this.additionalStopTypes = additionalStopTypes, this.additionalSerializers = additionalSerializers, this.additionalDeserializers = additionalDeserializers, this.additionalBlockDeserializers = additionalBlockDeserializers;
69
69
  }
70
70
  getSecretsNamespace() {
@@ -122,31 +122,37 @@ const pluginConfig = GTConfig.getInstance(), theme = theme$1.buildTheme(), BaseT
122
122
  !loadingSecrets && secrets && children
123
123
  ] });
124
124
  return /* @__PURE__ */ jsxRuntime.jsx(ui.ThemeProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsx(ui.ToastProvider, { paddingY: 7, children: showContainer ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding, children: content }) : content }) });
125
- }, reconcileArray = (origArray, translatedArray) => {
125
+ }, isRecord$4 = (value) => typeof value == "object" && value !== null && !Array.isArray(value), reconcileArray = (origArray, translatedArray) => {
126
126
  if (translatedArray && translatedArray.some((el) => typeof el == "string"))
127
127
  return translatedArray;
128
128
  const combined = JSON.parse(JSON.stringify(origArray));
129
- return translatedArray.forEach((block) => {
130
- if (!block._key)
129
+ return translatedArray.forEach((translatedItem) => {
130
+ if (!isRecord$4(translatedItem) || !translatedItem._key)
131
131
  return;
132
132
  const foundBlockIdx = origArray.findIndex(
133
- (origBlock) => origBlock._key === block._key
133
+ (origBlock) => isRecord$4(origBlock) && origBlock._key === translatedItem._key
134
134
  );
135
135
  foundBlockIdx < 0 ? console.warn(
136
136
  `This block no longer exists on the original document. Was it removed? ${JSON.stringify(
137
- block
137
+ translatedItem
138
138
  )}`
139
- ) : origArray[foundBlockIdx]._type === "block" || origArray[foundBlockIdx]._type === "span" ? combined[foundBlockIdx] = block : Array.isArray(origArray[foundBlockIdx]) ? combined[foundBlockIdx] = reconcileArray(origArray[foundBlockIdx], block) : combined[foundBlockIdx] = reconcileObject(
139
+ ) : isRecord$4(origArray[foundBlockIdx]) && (origArray[foundBlockIdx]._type === "block" || origArray[foundBlockIdx]._type === "span") ? combined[foundBlockIdx] = translatedItem : isRecord$4(origArray[foundBlockIdx]) && (combined[foundBlockIdx] = reconcileObject(
140
140
  origArray[foundBlockIdx],
141
- block
142
- );
141
+ translatedItem
142
+ ));
143
143
  }), combined;
144
144
  }, reconcileObject = (origObject, translatedObject) => {
145
145
  if (typeof translatedObject != "object" || !Object.keys(translatedObject).length)
146
146
  return origObject;
147
147
  const updatedObj = JSON.parse(JSON.stringify(origObject));
148
148
  return Object.entries(translatedObject).forEach(([key, value]) => {
149
- !value || key[0] === "_" || (typeof value == "string" ? updatedObj[key] = value : Array.isArray(value) ? updatedObj[key] = reconcileArray(origObject[key] ?? [], value) : updatedObj[key] = reconcileObject(origObject[key] ?? {}, value));
149
+ !value || key[0] === "_" || (typeof value == "string" ? updatedObj[key] = value : Array.isArray(value) ? updatedObj[key] = reconcileArray(
150
+ Array.isArray(origObject[key]) ? origObject[key] : [],
151
+ value
152
+ ) : isRecord$4(value) && (updatedObj[key] = reconcileObject(
153
+ isRecord$4(origObject[key]) ? origObject[key] : {},
154
+ value
155
+ )));
150
156
  }), updatedObj;
151
157
  }, fieldLevelMerge = (translatedFields, baseDoc, localeId, baseLang = "en") => {
152
158
  const merged = {};
@@ -161,8 +167,11 @@ const pluginConfig = GTConfig.getInstance(), theme = theme$1.buildTheme(), BaseT
161
167
  translatedFields
162
168
  )[0].value;
163
169
  let valToPatch;
164
- typeof translatedVal == "string" ? valToPatch = translatedVal : Array.isArray(translatedVal) && translatedVal.length ? valToPatch = reconcileArray(origVal ?? [], translatedVal) : typeof translatedVal == "object" && Object.keys(translatedVal).length && (valToPatch = reconcileObject(
165
- origVal ?? {},
170
+ typeof translatedVal == "string" ? valToPatch = translatedVal : Array.isArray(translatedVal) && translatedVal.length ? valToPatch = reconcileArray(
171
+ origVal ?? [],
172
+ translatedVal
173
+ ) : typeof translatedVal == "object" && Object.keys(translatedVal).length && (valToPatch = reconcileObject(
174
+ isRecord$4(origVal) ? origVal : {},
166
175
  translatedVal
167
176
  ));
168
177
  const destinationPath = [
@@ -173,7 +182,10 @@ const pluginConfig = GTConfig.getInstance(), theme = theme$1.buildTheme(), BaseT
173
182
  ];
174
183
  merged[mutator.arrayToJSONMatchPath(destinationPath)] = valToPatch;
175
184
  }), merged;
176
- }, documentLevelMerge = (translatedFields, baseDoc) => reconcileObject(baseDoc, translatedFields), BaseDocumentMerger = {
185
+ }, documentLevelMerge = (translatedFields, baseDoc) => reconcileObject(
186
+ baseDoc,
187
+ translatedFields
188
+ ), BaseDocumentMerger = {
177
189
  fieldLevelMerge,
178
190
  documentLevelMerge,
179
191
  reconcileArray,
@@ -240,7 +252,7 @@ function decode(base64) {
240
252
  bytes[i] = binary.charCodeAt(i);
241
253
  return new TextDecoder().decode(bytes);
242
254
  }
243
- const defaultStopTypes = [
255
+ const isRecord$3 = (value) => typeof value == "object" && value !== null && !Array.isArray(value), defaultStopTypes = [
244
256
  "reference",
245
257
  "date",
246
258
  "datetime",
@@ -283,13 +295,19 @@ const defaultStopTypes = [
283
295
  }, customDeserializers = { types: {} }, customBlockDeserializers = [
284
296
  // handle marks with data-gt-internal
285
297
  {
286
- deserialize(el, next2) {
298
+ deserialize(node2, next2) {
299
+ if (node2.nodeType !== 1)
300
+ return;
301
+ const el = node2;
287
302
  if (!el.hasChildNodes() || !el.getAttribute("data-gt-internal"))
288
303
  return;
289
304
  const { html, data } = detachGTData(el.outerHTML), block = blockTools.htmlToBlocks(html, blockContentType)[0], children = next2(el.childNodes);
290
305
  let markDefs = [];
291
- return "markDefs" in block && (markDefs = block.markDefs ?? []), data?.markDef && markDefs.push(data.markDef), children && children.forEach((child) => {
292
- child.marks = data?.markDef?._key ? [...child.marks || [], data.markDef._key] : [...child.marks || []];
306
+ return "markDefs" in block && (markDefs = block.markDefs ?? []), data?.markDef && markDefs.push(data.markDef), Array.isArray(children) && children.forEach((child) => {
307
+ if (!isRecord$3(child))
308
+ return;
309
+ const marks = Array.isArray(child.marks) ? child.marks : [];
310
+ child.marks = data?.markDef?._key ? [...marks, data.markDef._key] : marks;
293
311
  }), {
294
312
  ...block,
295
313
  markDefs,
@@ -299,7 +317,10 @@ const defaultStopTypes = [
299
317
  },
300
318
  //handle undeclared styles
301
319
  {
302
- deserialize(el, next2) {
320
+ deserialize(node2, next2) {
321
+ if (node2.nodeType !== 1)
322
+ return;
323
+ const el = node2;
303
324
  if (!el.hasChildNodes() || el.getAttribute("data-type") !== "unknown-block-style")
304
325
  return;
305
326
  const style = el.getAttribute("data-style") ?? "";
@@ -312,7 +333,10 @@ const defaultStopTypes = [
312
333
  },
313
334
  //handle list items
314
335
  {
315
- deserialize(el, next2) {
336
+ deserialize(node2, next2) {
337
+ if (node2.nodeType !== 1)
338
+ return;
339
+ const el = node2;
316
340
  if (!el.hasChildNodes() || el.tagName.toLowerCase() !== "li")
317
341
  return;
318
342
  const tagsToStyle = {
@@ -346,7 +370,7 @@ const defaultStopTypes = [
346
370
  };
347
371
  }
348
372
  }
349
- ], META_FIELDS$1 = ["_key", "_type", "_id"], languageObjectFieldFilter = (obj, baseLang) => {
373
+ ], META_FIELDS$1 = ["_key", "_type", "_id"], isRecord$2 = (value) => typeof value == "object" && value !== null && !Array.isArray(value), languageObjectFieldFilter = (obj, baseLang) => {
350
374
  const filterToLangField = (childObj) => {
351
375
  const filteredObj = {};
352
376
  return filteredObj[baseLang] = childObj[baseLang], META_FIELDS$1.forEach((field) => {
@@ -360,24 +384,29 @@ const defaultStopTypes = [
360
384
  for (const key in childObj)
361
385
  if (childObj.hasOwnProperty(key)) {
362
386
  const value = childObj[key];
363
- if (value.hasOwnProperty(baseLang))
387
+ if (isRecord$2(value) && Object.hasOwn(value, baseLang))
364
388
  filteredObj[key] = filterToLangField(value);
365
389
  else if (Array.isArray(value) && value.length && typeof value[0] == "object") {
366
- const validLangObjects = value.reduce((validArr, objInArray) => {
367
- if (objInArray._type === "block")
368
- validArr.push(objInArray);
369
- else if (objInArray.hasOwnProperty(baseLang))
370
- validArr.push(filterToLangField(objInArray));
371
- else {
372
- const filtered = findBaseLang(objInArray);
373
- Object.keys(filtered).filter(
374
- (objInArrayKey) => META_FIELDS$1.indexOf(objInArrayKey) === -1
375
- ).length && validArr.push(filtered);
376
- }
377
- return validArr;
378
- }, []);
390
+ const validLangObjects = value.reduce(
391
+ (validArr, objInArray) => {
392
+ if (!isRecord$2(objInArray))
393
+ return validArr;
394
+ if (objInArray._type === "block")
395
+ validArr.push(objInArray);
396
+ else if (Object.hasOwn(objInArray, baseLang))
397
+ validArr.push(filterToLangField(objInArray));
398
+ else {
399
+ const filtered = findBaseLang(objInArray);
400
+ Object.keys(filtered).filter(
401
+ (objInArrayKey) => META_FIELDS$1.indexOf(objInArrayKey) === -1
402
+ ).length && validArr.push(filtered);
403
+ }
404
+ return validArr;
405
+ },
406
+ []
407
+ );
379
408
  validLangObjects.length && (filteredObj[key] = validLangObjects);
380
- } else if (typeof value == "object") {
409
+ } else if (isRecord$2(value)) {
381
410
  const nestedLangObj = findBaseLang(value);
382
411
  Object.keys(nestedLangObj).filter(
383
412
  (nestedObjKey) => META_FIELDS$1.indexOf(nestedObjKey) === -1
@@ -388,18 +417,24 @@ const defaultStopTypes = [
388
417
  };
389
418
  return findBaseLang(obj);
390
419
  }, fieldFilter = (obj, objFields, stopTypes) => {
391
- const filteredObj = { _type: obj._type }, fieldFilterFunc = (field) => field.localize === !1 ? !1 : field.type === "string" || field.type === "text" || Array.isArray(obj[field.name]) ? !0 : !stopTypes.includes(field.type);
420
+ const filteredObj = {
421
+ _type: typeof obj._type == "string" ? obj._type : ""
422
+ }, fieldFilterFunc = (field) => {
423
+ const fieldMetadata = field, fieldType = typeof fieldMetadata.type == "string" ? fieldMetadata.type : fieldMetadata.type?.name;
424
+ return fieldMetadata.localize === !1 ? !1 : fieldType === "string" || fieldType === "text" || Array.isArray(obj[field.name]) ? !0 : !!(fieldType && !stopTypes.includes(fieldType));
425
+ };
392
426
  return [
393
427
  ...META_FIELDS$1,
394
428
  ...objFields.filter(fieldFilterFunc).map((field) => field.name)
395
429
  ].forEach((field) => {
396
430
  obj[field] && (filteredObj[field] = obj[field]);
397
431
  }), filteredObj;
398
- }, META_FIELDS = ["_key", "_type", "_id", "_weak"], BaseDocumentSerializer = (schemas) => {
432
+ }, META_FIELDS = ["_key", "_type", "_id", "_weak"], isRecord$1 = (value) => typeof value == "object" && value !== null && !Array.isArray(value), BaseDocumentSerializer = (schemas) => {
399
433
  const getSchema = (name) => schemas?._original?.types.find((s) => s.name === name), serializeObject = (obj, stopTypes, serializers) => {
400
434
  if (stopTypes.includes(obj._type))
401
435
  return "";
402
- if (serializers.types && Object.keys(serializers.types).includes(obj._type))
436
+ const typeSerializers = isRecord$1(serializers.types) ? serializers.types : {};
437
+ if (Object.keys(typeSerializers).includes(obj._type))
403
438
  return toHtml.toHTML([obj], { components: serializers });
404
439
  if (obj._type === "span" || obj._type === "block")
405
440
  return toHtml.toHTML(obj, { components: serializers });
@@ -420,9 +455,9 @@ const defaultStopTypes = [
420
455
  else if (Array.isArray(value))
421
456
  htmlField = serializeArray(value, fieldName, stopTypes, {
422
457
  ...serializers,
423
- types: { ...serializers.types }
458
+ types: { ...typeSerializers }
424
459
  });
425
- else {
460
+ else if (isRecord$1(value)) {
426
461
  const embeddedObject = value, embeddedObjectSchema = getSchema(embeddedObject._type);
427
462
  let toTranslate = embeddedObject;
428
463
  embeddedObjectSchema && embeddedObjectSchema.fields && (toTranslate = fieldFilter(
@@ -432,7 +467,7 @@ const defaultStopTypes = [
432
467
  ));
433
468
  const objHTML = serializeObject(toTranslate, stopTypes, {
434
469
  ...serializers,
435
- types: { ...serializers.types }
470
+ types: { ...typeSerializers }
436
471
  });
437
472
  htmlField = `<div class="${fieldName}" data-level="field">${objHTML}</div>`;
438
473
  }
@@ -450,7 +485,7 @@ const defaultStopTypes = [
450
485
  components: {
451
486
  ...serializers,
452
487
  types: {
453
- ...serializers.types,
488
+ ...typeSerializers,
454
489
  ...newSerializationMethods
455
490
  }
456
491
  }
@@ -463,9 +498,13 @@ const defaultStopTypes = [
463
498
  return serializedBlock;
464
499
  }, serializeArray = (fieldContent, fieldName, stopTypes, serializers) => {
465
500
  const output = fieldContent.filter(
466
- (block) => !stopTypes.includes(block._type)
501
+ (block) => typeof block == "string" || typeof block._type != "string" || !stopTypes.includes(block._type)
467
502
  ).map((block) => {
468
- const schema2 = getSchema(block._type);
503
+ if (typeof block == "string")
504
+ return block;
505
+ const schema2 = getSchema(
506
+ typeof block._type == "string" ? block._type : ""
507
+ );
469
508
  return schema2 && schema2.fields ? fieldFilter(block, schema2.fields, stopTypes) : block;
470
509
  }).map((obj) => typeof obj == "string" ? `<span>${obj}</span>` : serializeObject(obj, stopTypes, serializers));
471
510
  return `<div class="${fieldName}" data-type="array">${output.join("")}</div>`;
@@ -483,12 +522,14 @@ const defaultStopTypes = [
483
522
  serializedFields[key] = value;
484
523
  else if (Array.isArray(value))
485
524
  serializedFields[key] = serializeArray(
486
- value,
525
+ value.filter(
526
+ (item) => typeof item == "string" || isRecord$1(item)
527
+ ),
487
528
  key,
488
529
  stopTypes,
489
530
  serializers
490
531
  );
491
- else if (value && !stopTypes.find((stopType) => stopType == value?._type)) {
532
+ else if (value && isRecord$1(value) && !stopTypes.find((stopType) => stopType == value?._type)) {
492
533
  const serialized = serializeObject(
493
534
  value,
494
535
  stopTypes,
@@ -534,13 +575,22 @@ const deserializeArray = (arrayHTML, deserializers = customDeserializers, blockD
534
575
  return Array.from(arrayHTML.children).forEach((child) => {
535
576
  let deserializedObject;
536
577
  try {
537
- child.tagName?.toLowerCase() === "span" ? deserializedObject = preprocess(child.innerHTML) : child.className || child.getAttribute("data-type") === "object" ? (deserializedObject = deserializeObject(
538
- child,
539
- deserializers,
540
- blockDeserializers
541
- ), deserializedObject._key = child.id) : (deserializedObject = blockTools.htmlToBlocks(child.outerHTML, blockContentType, {
542
- rules: blockDeserializers
543
- }), deserializedObject = mergeBlocks(deserializedObject), deserializedObject._key = child.id);
578
+ if (child.tagName?.toLowerCase() === "span")
579
+ deserializedObject = preprocess(child.innerHTML);
580
+ else if (child.className || child.getAttribute("data-type") === "object")
581
+ deserializedObject = deserializeObject(
582
+ child,
583
+ deserializers,
584
+ blockDeserializers
585
+ ), deserializedObject && typeof deserializedObject == "object" && !Array.isArray(deserializedObject) && (deserializedObject._key = child.id);
586
+ else {
587
+ const blocks = blockTools.htmlToBlocks(child.outerHTML, blockContentType, {
588
+ rules: blockDeserializers
589
+ });
590
+ deserializedObject = mergeBlocks(
591
+ blocks
592
+ ), deserializedObject._key = child.id;
593
+ }
544
594
  } catch (e) {
545
595
  console.debug(
546
596
  `Tried to deserialize block: ${child.outerHTML} in an array but failed to identify it! Error: ${e}`
@@ -549,7 +599,7 @@ const deserializeArray = (arrayHTML, deserializers = customDeserializers, blockD
549
599
  output.push(deserializedObject);
550
600
  }), output;
551
601
  }, deserializeObject = (objectHTML, deserializers = customDeserializers, blockDeserializers = customBlockDeserializers) => {
552
- const deserialize = deserializers.types[objectHTML.className];
602
+ const deserialize = deserializers.types?.[objectHTML.className];
553
603
  if (deserialize)
554
604
  return deserialize(objectHTML);
555
605
  const output = {};
@@ -576,7 +626,7 @@ const deserializeArray = (arrayHTML, deserializers = customDeserializers, blockD
576
626
  if (HTMLnode?.getAttribute("data-level") === "field" && (HTMLnode = HTMLnode.children[0]), !HTMLnode)
577
627
  return {};
578
628
  let output;
579
- const deserialize = deserializers.types[HTMLnode.className];
629
+ const deserialize = deserializers.types?.[HTMLnode.className];
580
630
  return deserialize ? output = deserialize(HTMLnode) : HTMLnode.getAttribute("data-type") === "object" ? output = deserializeObject(HTMLnode, deserializers, blockDeserializers) : HTMLnode.getAttribute("data-type") === "array" ? output = deserializeArray(HTMLnode, deserializers, blockDeserializers) : (output = {}, console.debug(
581
631
  `Tried to deserialize block ${HTMLnode.outerHTML} but failed to identify it!`
582
632
  )), output;
@@ -615,7 +665,7 @@ function forEachMatchingField(documentId, document2, fields, callback) {
615
665
  });
616
666
  results && results.length > 0 && results.forEach(
617
667
  (result) => {
618
- type !== void 0 ? typeof result.value == "object" && result.value !== null && result.value._type === type && callback(result) : callback(result);
668
+ type !== void 0 ? typeof result.value == "object" && result.value !== null && !Array.isArray(result.value) && result.value._type === type && callback(result) : callback(result);
619
669
  }
620
670
  );
621
671
  } catch (error) {
@@ -649,10 +699,17 @@ function applyDocuments(documentId, sourceDocument, targetDocument, ignore, skip
649
699
  }), deleteMatchingFields(documentId, mergedDocument, skip), mergedDocument;
650
700
  }
651
701
  function dedupeFieldValue(value, localeId) {
652
- return localeId ? typeof value == "string" ? appendLocaleSuffix(value, localeId) : value && typeof value == "object" && !Array.isArray(value) && typeof value.current == "string" ? {
653
- ...value,
654
- current: appendLocaleSuffix(value.current, localeId)
655
- } : value : value;
702
+ if (!localeId) return value;
703
+ if (typeof value == "string")
704
+ return appendLocaleSuffix(value, localeId);
705
+ if (value && typeof value == "object" && !Array.isArray(value) && typeof value.current == "string") {
706
+ const slug = value;
707
+ return {
708
+ ...slug,
709
+ current: appendLocaleSuffix(slug.current, localeId)
710
+ };
711
+ }
712
+ return value;
656
713
  }
657
714
  function appendLocaleSuffix(value, localeId) {
658
715
  if (!value) return value;
@@ -976,7 +1033,9 @@ const documentLevelPatch = async (docInfo, translatedFields, localeId, client, l
976
1033
  baseDoc,
977
1034
  client,
978
1035
  baseLanguage
979
- )).translations.find((translation) => translation.language === localeId)?.value?._ref;
1036
+ )).translations.find(
1037
+ (translation) => translation.language === localeId
1038
+ )?.value?._ref;
980
1039
  i18nDocId && (i18nDoc = await findLatestDraft(i18nDocId, client)), mergeWithTargetLocale && i18nDoc ? baseDoc = i18nDoc : docInfo.documentId && docInfo.versionId && (baseDoc = await findDocumentAtRevision(
981
1040
  docInfo.documentId,
982
1041
  docInfo.versionId,
@@ -1002,7 +1061,9 @@ const documentLevelPatch = async (docInfo, translatedFields, localeId, client, l
1002
1061
  baseDoc,
1003
1062
  client,
1004
1063
  baseLanguage
1005
- ), freshI18nDocId = freshTranslationMetadata.translations.find((translation) => translation.language === localeId)?.value?._ref;
1064
+ ), freshI18nDocId = freshTranslationMetadata.translations.find(
1065
+ (translation) => translation.language === localeId
1066
+ )?.value?._ref;
1006
1067
  if (freshI18nDocId) {
1007
1068
  const freshI18nDoc = await findLatestDraft(freshI18nDocId, client);
1008
1069
  await patchI18nDoc(
@@ -1039,6 +1100,7 @@ async function importDocument(docInfo, localeId, document2, context, mergeWithTa
1039
1100
  mergeWithTargetLocale
1040
1101
  );
1041
1102
  }
1103
+ const isRecord = (value) => typeof value == "object" && value !== null && !Array.isArray(value), isReference = (value) => isRecord(value) && value._type === "reference" && typeof value._ref == "string";
1042
1104
  async function resolveRefs(doc, locale, client) {
1043
1105
  const references = findReferences(doc);
1044
1106
  if (references.length === 0)
@@ -1054,9 +1116,9 @@ function findReferences(obj, path = []) {
1054
1116
  if (!obj || typeof obj != "object")
1055
1117
  return [];
1056
1118
  const references = [];
1057
- return obj._ref && references.push({ ref: obj, path }), Array.isArray(obj) ? obj.forEach((item, index) => {
1119
+ return isReference(obj) && references.push({ ref: obj, path }), Array.isArray(obj) ? obj.forEach((item, index) => {
1058
1120
  references.push(...findReferences(item, [...path, index.toString()]));
1059
- }) : Object.keys(obj).forEach((key) => {
1121
+ }) : isRecord(obj) && Object.keys(obj).forEach((key) => {
1060
1122
  references.push(...findReferences(obj[key], [...path, key]));
1061
1123
  }), references;
1062
1124
  }
@@ -1080,7 +1142,7 @@ function updateDocumentReferences(doc, translatedRefs) {
1080
1142
  function updateReferencesRecursive(obj, translatedRefs) {
1081
1143
  if (!obj || typeof obj != "object")
1082
1144
  return obj;
1083
- if (obj._ref && translatedRefs.has(obj._ref))
1145
+ if (isReference(obj) && translatedRefs.has(obj._ref))
1084
1146
  return {
1085
1147
  ...obj,
1086
1148
  _ref: translatedRefs.get(obj._ref)
@@ -1089,7 +1151,10 @@ function updateReferencesRecursive(obj, translatedRefs) {
1089
1151
  return obj.map((item) => updateReferencesRecursive(item, translatedRefs));
1090
1152
  const updated = {};
1091
1153
  return Object.keys(obj).forEach((key) => {
1092
- updated[key] = updateReferencesRecursive(obj[key], translatedRefs);
1154
+ updated[key] = updateReferencesRecursive(
1155
+ obj[key],
1156
+ translatedRefs
1157
+ );
1093
1158
  }), updated;
1094
1159
  }
1095
1160
  async function findTranslatedDocumentForLocale(sourceDocumentId, localeId, client) {
@@ -1202,16 +1267,19 @@ async function getReadyFilesForImport(translationStatuses, options = {}) {
1202
1267
  async function importTranslations(readyFiles, secrets, translationContext, options = {}) {
1203
1268
  if (readyFiles.length === 0)
1204
1269
  return { successCount: 0, failureCount: 0, successfulImports: [] };
1205
- const importItems = (await downloadTranslations(readyFiles, secrets)).map((file) => ({
1206
- docInfo: {
1207
- documentId: file.fileId,
1208
- versionId: file.versionId
1209
- },
1210
- locale: file.locale,
1211
- data: file.data,
1212
- translationContext,
1213
- key: `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`
1214
- })), result = await processImportBatch(importItems, {
1270
+ const importItems = (await downloadTranslations(readyFiles, secrets)).map((file) => {
1271
+ const data = typeof file.data == "string" ? file.data : JSON.stringify(file.data ?? "");
1272
+ return {
1273
+ docInfo: {
1274
+ documentId: file.fileId,
1275
+ versionId: file.versionId
1276
+ },
1277
+ locale: file.locale,
1278
+ data,
1279
+ translationContext,
1280
+ key: `${file.branchId}:${file.fileId}:${file.versionId}:${file.locale}`
1281
+ };
1282
+ }), result = await processImportBatch(importItems, {
1215
1283
  onProgress: options.onProgress,
1216
1284
  onItemSuccess: (item, key) => {
1217
1285
  options.onImportSuccess?.(key);
@@ -1297,7 +1365,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1297
1365
  setDocuments(dedupeDocumentsPreferDraft(docs));
1298
1366
  } catch {
1299
1367
  toast.push({
1300
- title: "Error fetching documents",
1368
+ title: "Documents could not be loaded. Check your Sanity connection and try refreshing.",
1301
1369
  status: "error",
1302
1370
  closable: !0
1303
1371
  });
@@ -1311,7 +1379,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1311
1379
  setLocales(availableLocales);
1312
1380
  } catch {
1313
1381
  toast.push({
1314
- title: "Error fetching locales",
1382
+ title: "Locales could not be loaded. Check your General Translation credentials and try again.",
1315
1383
  status: "error",
1316
1384
  closable: !0
1317
1385
  });
@@ -1343,7 +1411,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1343
1411
  }), setExistingTranslations(existing);
1344
1412
  } catch (error) {
1345
1413
  console.error("Error fetching existing translations:", error), toast.push({
1346
- title: "Error fetching existing translations",
1414
+ title: "Existing translations could not be loaded. Try refreshing before importing.",
1347
1415
  status: "error",
1348
1416
  closable: !0
1349
1417
  });
@@ -1379,7 +1447,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1379
1447
  });
1380
1448
  } catch {
1381
1449
  toast.push({
1382
- title: "Error creating translation tasks",
1450
+ title: "Translation tasks could not be created. No documents were changed. Try again or check the console for details.",
1383
1451
  status: "error",
1384
1452
  closable: !0
1385
1453
  });
@@ -1435,7 +1503,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1435
1503
  });
1436
1504
  } catch (error) {
1437
1505
  console.error("Error importing translations:", error), toast.push({
1438
- title: "Error importing translations",
1506
+ title: "Translations could not be imported. No documents were changed. Try again or check the console for details.",
1439
1507
  status: "error",
1440
1508
  closable: !0
1441
1509
  });
@@ -1537,7 +1605,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1537
1605
  });
1538
1606
  } catch (error) {
1539
1607
  console.error("Error importing missing translations:", error), toast.push({
1540
- title: "Error importing missing translations",
1608
+ title: "Missing translations could not be imported. No documents were changed. Try again or check the console for details.",
1541
1609
  status: "error",
1542
1610
  closable: !0
1543
1611
  });
@@ -1623,7 +1691,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1623
1691
  });
1624
1692
  } catch (error) {
1625
1693
  console.error("Error refreshing translation status:", error), toast.push({
1626
- title: "Error refreshing translation status",
1694
+ title: "Translation status could not be refreshed. Try again before importing.",
1627
1695
  status: "error",
1628
1696
  closable: !0
1629
1697
  });
@@ -1698,7 +1766,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1698
1766
  });
1699
1767
  } catch (importError) {
1700
1768
  console.error("Failed to import translation:", importError), toast.push({
1701
- title: `Failed to import translation for ${documentId} (${localeId})`,
1769
+ title: `Translation for ${documentId} (${localeId}) could not be imported. This document was not changed.`,
1702
1770
  status: "error",
1703
1771
  closable: !0
1704
1772
  });
@@ -1711,7 +1779,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1711
1779
  });
1712
1780
  } catch (error) {
1713
1781
  console.error("Error importing translation:", error), toast.push({
1714
- title: `Error importing translation for ${documentId}`,
1782
+ title: `Translation for ${documentId} could not be imported. This document was not changed.`,
1715
1783
  status: "error",
1716
1784
  closable: !0
1717
1785
  });
@@ -1785,7 +1853,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1785
1853
  }), patchedCount;
1786
1854
  } catch (error) {
1787
1855
  return console.error("Error patching document references:", error), toast.push({
1788
- title: "Error patching document references",
1856
+ title: "Document references could not be updated. Imported translations may need to be linked manually.",
1789
1857
  status: "error",
1790
1858
  closable: !0
1791
1859
  }), 0;
@@ -1840,7 +1908,7 @@ const getLocales = async (_secrets) => pluginConfig.getLocales().map((locale) =>
1840
1908
  }), translatedDocumentIds.length;
1841
1909
  } catch (error) {
1842
1910
  return console.error("Error publishing translations:", error), toast.push({
1843
- title: "Error publishing translations",
1911
+ title: "Translations could not be published. No unpublished source documents were changed.",
1844
1912
  status: "error",
1845
1913
  closable: !0
1846
1914
  }), 0;