@easyling/sanity-connector 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +560 -90
  2. package/dist/index.js +2 -1
  3. package/dist/index.js.map +1 -0
  4. package/package.json +38 -54
  5. package/LICENSE +0 -21
  6. package/dist/.tsbuildinfo +0 -1
  7. package/dist-types/actions/bulkTranslate.d.ts +0 -6
  8. package/dist-types/actions/manageDNTFields.d.ts +0 -11
  9. package/dist-types/actions/translateDocument.d.ts +0 -6
  10. package/dist-types/components/RadioWithDefault.d.ts +0 -16
  11. package/dist-types/components/auth/AuthNavbar.d.ts +0 -17
  12. package/dist-types/components/auth/AuthStatus.d.ts +0 -26
  13. package/dist-types/components/auth/AuthStatusWrapper.d.ts +0 -14
  14. package/dist-types/components/auth/MigrationPrompt.d.ts +0 -19
  15. package/dist-types/components/auth/MigrationPromptWrapper.d.ts +0 -13
  16. package/dist-types/components/auth/OAuthCallback.d.ts +0 -19
  17. package/dist-types/components/auth/index.d.ts +0 -14
  18. package/dist-types/components/config/LocaleConfigTool.d.ts +0 -16
  19. package/dist-types/components/config/LocaleConfigToolWrapper.d.ts +0 -12
  20. package/dist-types/components/config/OAuthConfig.d.ts +0 -25
  21. package/dist-types/components/config/OAuthConfigWrapper.d.ts +0 -12
  22. package/dist-types/components/config/PasswordInput.d.ts +0 -13
  23. package/dist-types/components/config/index.d.ts +0 -8
  24. package/dist-types/components/config/localeConfigToolDefinition.d.ts +0 -12
  25. package/dist-types/components/config/oauthConfigToolDefinition.d.ts +0 -12
  26. package/dist-types/components/dialogs/ConfirmationDialog.d.ts +0 -20
  27. package/dist-types/components/dialogs/ErrorDialog.d.ts +0 -20
  28. package/dist-types/components/dialogs/LocaleSelectionDialog.d.ts +0 -62
  29. package/dist-types/components/dialogs/SuccessDialog.d.ts +0 -18
  30. package/dist-types/components/dialogs/index.d.ts +0 -11
  31. package/dist-types/components/dnt/DNTFieldBadge.d.ts +0 -15
  32. package/dist-types/components/dnt/DNTFieldComponent.d.ts +0 -16
  33. package/dist-types/components/dnt/DNTFieldInput.d.ts +0 -13
  34. package/dist-types/components/dnt/DebugDNTBadge.d.ts +0 -19
  35. package/dist-types/components/dnt/index.d.ts +0 -7
  36. package/dist-types/config/index.d.ts +0 -5
  37. package/dist-types/config/pluginConfig.d.ts +0 -162
  38. package/dist-types/index.d.ts +0 -11
  39. package/dist-types/plugin.d.ts +0 -12
  40. package/dist-types/services/authStateManager.d.ts +0 -93
  41. package/dist-types/services/collisionDetectionService.d.ts +0 -85
  42. package/dist-types/services/contentExtractor.d.ts +0 -161
  43. package/dist-types/services/dialogService.d.ts +0 -95
  44. package/dist-types/services/dntServiceManager.d.ts +0 -43
  45. package/dist-types/services/dntStorageAdapter.d.ts +0 -72
  46. package/dist-types/services/documentCreationService.d.ts +0 -262
  47. package/dist-types/services/localeService.d.ts +0 -159
  48. package/dist-types/services/localeStorageAdapter.d.ts +0 -41
  49. package/dist-types/services/oauthConfigStorage.d.ts +0 -45
  50. package/dist-types/services/oauthService.d.ts +0 -47
  51. package/dist-types/services/oauthServiceManager.d.ts +0 -195
  52. package/dist-types/services/tokenStorage.d.ts +0 -53
  53. package/dist-types/services/translationService.d.ts +0 -385
  54. package/dist-types/services/unifiedConfigStorage.d.ts +0 -158
  55. package/dist-types/test-utils.d.ts +0 -8
  56. package/dist-types/types/dialog.d.ts +0 -118
  57. package/dist-types/types/dnt.d.ts +0 -83
  58. package/dist-types/types/index.d.ts +0 -11
  59. package/dist-types/types/locale.d.ts +0 -115
  60. package/dist-types/types/oauth.d.ts +0 -89
  61. package/dist-types/types/pluginConfig.d.ts +0 -64
  62. package/dist-types/types/translation.d.ts +0 -121
  63. package/dist-types/utils/dntDefaults.d.ts +0 -101
  64. package/dist-types/utils/htmlFormatter.d.ts +0 -65
  65. package/dist-types/utils/index.d.ts +0 -16
  66. package/dist-types/utils/logger.d.ts +0 -104
  67. package/dist-types/utils/oauthErrorFeedback.d.ts +0 -75
  68. package/dist-types/utils/oauthLogger.d.ts +0 -175
  69. package/dist-types/utils/validator.d.ts +0 -66
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","mappings":"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","sources":["webpack://@easyling/sanity-connector/../node_modules/@easyling/protos-sanity/dist/generated/translation_request.js","webpack://@easyling/sanity-connector/../node_modules/@easyling/protos-sanity/dist/generated/translation_response.js","webpack://@easyling/sanity-connector/../node_modules/@protobufjs/aspromise/index.js","webpack://@easyling/sanity-connector/../node_modules/@protobufjs/base64/index.js","webpack://@easyling/sanity-connector/../node_modules/@protobufjs/eventemitter/index.js","webpack://@easyling/sanity-connector/../node_modules/@protobufjs/float/index.js","webpack://@easyling/sanity-connector/../node_modules/@protobufjs/inquire/index.js","webpack://@easyling/sanity-connector/../node_modules/@protobufjs/pool/index.js","webpack://@easyling/sanity-connector/../node_modules/@protobufjs/utf8/index.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/minimal.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/src/index-minimal.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/src/reader.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/src/reader_buffer.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/src/roots.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/src/rpc.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/src/rpc/service.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/src/util/longbits.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/src/util/minimal.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/src/writer.js","webpack://@easyling/sanity-connector/../node_modules/protobufjs/src/writer_buffer.js","webpack://@easyling/sanity-connector/webpack/bootstrap","webpack://@easyling/sanity-connector/webpack/runtime/define property getters","webpack://@easyling/sanity-connector/webpack/runtime/global","webpack://@easyling/sanity-connector/webpack/runtime/hasOwnProperty shorthand","webpack://@easyling/sanity-connector/./src/services/dntStorageAdapter.ts","webpack://@easyling/sanity-connector/./src/services/unifiedConfigStorage.ts","webpack://@easyling/sanity-connector/./src/services/dntServiceManager.ts","webpack://@easyling/sanity-connector/../shared/src/services/contentExtractor.ts","webpack://@easyling/sanity-connector/../shared/src/services/translationService.ts","webpack://@easyling/sanity-connector/../shared/src/services/collisionDetectionService.ts","webpack://@easyling/sanity-connector/../shared/src/services/documentCreationService.ts","webpack://@easyling/sanity-connector/../shared/src/services/unifiedConfigStorage.ts","webpack://@easyling/sanity-connector/../shared/src/utils/htmlFormatter.ts","webpack://@easyling/sanity-connector/../shared/src/utils/validator.ts","webpack://@easyling/sanity-connector/./src/services/contentExtractor.ts","webpack://@easyling/sanity-connector/./src/services/collisionDetectionService.ts","webpack://@easyling/sanity-connector/./src/services/documentCreationService.ts","webpack://@easyling/sanity-connector/./src/types/locale.ts","webpack://@easyling/sanity-connector/./src/components/RadioWithDefault.tsx","webpack://@easyling/sanity-connector/./src/config/pluginConfig.ts","webpack://@easyling/sanity-connector/./src/services/localeService.ts","webpack://@easyling/sanity-connector/./src/services/localeStorageAdapter.ts","webpack://@easyling/sanity-connector/./src/components/dialogs/ConfirmationDialog.tsx","webpack://@easyling/sanity-connector/./src/components/dialogs/SuccessDialog.tsx","webpack://@easyling/sanity-connector/./src/components/dialogs/ErrorDialog.tsx","webpack://@easyling/sanity-connector/./src/components/dialogs/LocaleSelectionDialog.tsx","webpack://@easyling/sanity-connector/./src/services/dialogService.tsx","webpack://@easyling/sanity-connector/./src/types/oauth.ts","webpack://@easyling/sanity-connector/./src/services/oauthService.ts","webpack://@easyling/sanity-connector/./src/services/tokenStorage.ts","webpack://@easyling/sanity-connector/./src/services/authStateManager.ts","webpack://@easyling/sanity-connector/./src/services/oauthConfigStorage.ts","webpack://@easyling/sanity-connector/./src/services/oauthServiceManager.ts","webpack://@easyling/sanity-connector/./src/actions/translateDocument.ts","webpack://@easyling/sanity-connector/./src/actions/bulkTranslate.tsx","webpack://@easyling/sanity-connector/./src/actions/manageDNTFields.tsx","webpack://@easyling/sanity-connector/./src/components/config/PasswordInput.tsx","webpack://@easyling/sanity-connector/./src/components/dnt/DNTFieldBadge.tsx","webpack://@easyling/sanity-connector/./src/components/dnt/DNTFieldComponent.tsx","webpack://@easyling/sanity-connector/./src/components/dnt/DNTFieldInput.tsx","webpack://@easyling/sanity-connector/./src/utils/dntDefaults.ts","webpack://@easyling/sanity-connector/./src/components/dnt/DebugDNTBadge.tsx","webpack://@easyling/sanity-connector/./src/plugin.tsx"],"sourcesContent":["\"use strict\";\n// Code generated by protoc-gen-ts_proto. DO NOT EDIT.\n// versions:\n// protoc-gen-ts_proto v1.181.2\n// protoc v3.21.8\n// source: translation_request.proto\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Metadata = exports.TranslatableField = exports.Content_FieldsEntry = exports.Content = exports.TranslationRequestPayload = exports.protobufPackage = void 0;\n/* eslint-disable */\nconst minimal_1 = __importDefault(require(\"protobufjs/minimal\"));\nexports.protobufPackage = \"hu.skawa.pagetranslate.server.model.protobuffers\";\nfunction createBaseTranslationRequestPayload() {\n return { content: undefined, project: \"\", format: \"\", metadata: undefined };\n}\nexports.TranslationRequestPayload = {\n encode(message, writer = minimal_1.default.Writer.create()) {\n if (message.content !== undefined) {\n exports.Content.encode(message.content, writer.uint32(10).fork()).ldelim();\n }\n if (message.project !== \"\") {\n writer.uint32(34).string(message.project);\n }\n if (message.format !== \"\") {\n writer.uint32(18).string(message.format);\n }\n if (message.metadata !== undefined) {\n exports.Metadata.encode(message.metadata, writer.uint32(26).fork()).ldelim();\n }\n return writer;\n },\n decode(input, length) {\n const reader = input instanceof minimal_1.default.Reader ? input : minimal_1.default.Reader.create(input);\n let end = length === undefined ? reader.len : reader.pos + length;\n const message = createBaseTranslationRequestPayload();\n while (reader.pos < end) {\n const tag = reader.uint32();\n switch (tag >>> 3) {\n case 1:\n if (tag !== 10) {\n break;\n }\n message.content = exports.Content.decode(reader, reader.uint32());\n continue;\n case 4:\n if (tag !== 34) {\n break;\n }\n message.project = reader.string();\n continue;\n case 2:\n if (tag !== 18) {\n break;\n }\n message.format = reader.string();\n continue;\n case 3:\n if (tag !== 26) {\n break;\n }\n message.metadata = exports.Metadata.decode(reader, reader.uint32());\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) {\n break;\n }\n reader.skipType(tag & 7);\n }\n return message;\n },\n fromJSON(object) {\n return {\n content: isSet(object.content) ? exports.Content.fromJSON(object.content) : undefined,\n project: isSet(object.project) ? globalThis.String(object.project) : \"\",\n format: isSet(object.format) ? globalThis.String(object.format) : \"\",\n metadata: isSet(object.metadata) ? exports.Metadata.fromJSON(object.metadata) : undefined,\n };\n },\n toJSON(message) {\n const obj = {};\n if (message.content !== undefined) {\n obj.content = exports.Content.toJSON(message.content);\n }\n if (message.project !== \"\") {\n obj.project = message.project;\n }\n if (message.format !== \"\") {\n obj.format = message.format;\n }\n if (message.metadata !== undefined) {\n obj.metadata = exports.Metadata.toJSON(message.metadata);\n }\n return obj;\n },\n create(base) {\n return exports.TranslationRequestPayload.fromPartial(base ?? {});\n },\n fromPartial(object) {\n const message = createBaseTranslationRequestPayload();\n message.content = (object.content !== undefined && object.content !== null)\n ? exports.Content.fromPartial(object.content)\n : undefined;\n message.project = object.project ?? \"\";\n message.format = object.format ?? \"\";\n message.metadata = (object.metadata !== undefined && object.metadata !== null)\n ? exports.Metadata.fromPartial(object.metadata)\n : undefined;\n return message;\n },\n};\nfunction createBaseContent() {\n return { body: \"\", title: \"\", slug: \"\", fields: {} };\n}\nexports.Content = {\n encode(message, writer = minimal_1.default.Writer.create()) {\n if (message.body !== \"\") {\n writer.uint32(10).string(message.body);\n }\n if (message.title !== \"\") {\n writer.uint32(18).string(message.title);\n }\n if (message.slug !== \"\") {\n writer.uint32(26).string(message.slug);\n }\n Object.entries(message.fields).forEach(([key, value]) => {\n exports.Content_FieldsEntry.encode({ key: key, value }, writer.uint32(34).fork()).ldelim();\n });\n return writer;\n },\n decode(input, length) {\n const reader = input instanceof minimal_1.default.Reader ? input : minimal_1.default.Reader.create(input);\n let end = length === undefined ? reader.len : reader.pos + length;\n const message = createBaseContent();\n while (reader.pos < end) {\n const tag = reader.uint32();\n switch (tag >>> 3) {\n case 1:\n if (tag !== 10) {\n break;\n }\n message.body = reader.string();\n continue;\n case 2:\n if (tag !== 18) {\n break;\n }\n message.title = reader.string();\n continue;\n case 3:\n if (tag !== 26) {\n break;\n }\n message.slug = reader.string();\n continue;\n case 4:\n if (tag !== 34) {\n break;\n }\n const entry4 = exports.Content_FieldsEntry.decode(reader, reader.uint32());\n if (entry4.value !== undefined) {\n message.fields[entry4.key] = entry4.value;\n }\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) {\n break;\n }\n reader.skipType(tag & 7);\n }\n return message;\n },\n fromJSON(object) {\n return {\n body: isSet(object.body) ? globalThis.String(object.body) : \"\",\n title: isSet(object.title) ? globalThis.String(object.title) : \"\",\n slug: isSet(object.slug) ? globalThis.String(object.slug) : \"\",\n fields: isObject(object.fields)\n ? Object.entries(object.fields).reduce((acc, [key, value]) => {\n acc[key] = exports.TranslatableField.fromJSON(value);\n return acc;\n }, {})\n : {},\n };\n },\n toJSON(message) {\n const obj = {};\n if (message.body !== \"\") {\n obj.body = message.body;\n }\n if (message.title !== \"\") {\n obj.title = message.title;\n }\n if (message.slug !== \"\") {\n obj.slug = message.slug;\n }\n if (message.fields) {\n const entries = Object.entries(message.fields);\n if (entries.length > 0) {\n obj.fields = {};\n entries.forEach(([k, v]) => {\n obj.fields[k] = exports.TranslatableField.toJSON(v);\n });\n }\n }\n return obj;\n },\n create(base) {\n return exports.Content.fromPartial(base ?? {});\n },\n fromPartial(object) {\n const message = createBaseContent();\n message.body = object.body ?? \"\";\n message.title = object.title ?? \"\";\n message.slug = object.slug ?? \"\";\n message.fields = Object.entries(object.fields ?? {}).reduce((acc, [key, value]) => {\n if (value !== undefined) {\n acc[key] = exports.TranslatableField.fromPartial(value);\n }\n return acc;\n }, {});\n return message;\n },\n};\nfunction createBaseContent_FieldsEntry() {\n return { key: \"\", value: undefined };\n}\nexports.Content_FieldsEntry = {\n encode(message, writer = minimal_1.default.Writer.create()) {\n if (message.key !== \"\") {\n writer.uint32(10).string(message.key);\n }\n if (message.value !== undefined) {\n exports.TranslatableField.encode(message.value, writer.uint32(18).fork()).ldelim();\n }\n return writer;\n },\n decode(input, length) {\n const reader = input instanceof minimal_1.default.Reader ? input : minimal_1.default.Reader.create(input);\n let end = length === undefined ? reader.len : reader.pos + length;\n const message = createBaseContent_FieldsEntry();\n while (reader.pos < end) {\n const tag = reader.uint32();\n switch (tag >>> 3) {\n case 1:\n if (tag !== 10) {\n break;\n }\n message.key = reader.string();\n continue;\n case 2:\n if (tag !== 18) {\n break;\n }\n message.value = exports.TranslatableField.decode(reader, reader.uint32());\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) {\n break;\n }\n reader.skipType(tag & 7);\n }\n return message;\n },\n fromJSON(object) {\n return {\n key: isSet(object.key) ? globalThis.String(object.key) : \"\",\n value: isSet(object.value) ? exports.TranslatableField.fromJSON(object.value) : undefined,\n };\n },\n toJSON(message) {\n const obj = {};\n if (message.key !== \"\") {\n obj.key = message.key;\n }\n if (message.value !== undefined) {\n obj.value = exports.TranslatableField.toJSON(message.value);\n }\n return obj;\n },\n create(base) {\n return exports.Content_FieldsEntry.fromPartial(base ?? {});\n },\n fromPartial(object) {\n const message = createBaseContent_FieldsEntry();\n message.key = object.key ?? \"\";\n message.value = (object.value !== undefined && object.value !== null)\n ? exports.TranslatableField.fromPartial(object.value)\n : undefined;\n return message;\n },\n};\nfunction createBaseTranslatableField() {\n return { value: \"\", dnt: false, type: \"\", path: \"\" };\n}\nexports.TranslatableField = {\n encode(message, writer = minimal_1.default.Writer.create()) {\n if (message.value !== \"\") {\n writer.uint32(10).string(message.value);\n }\n if (message.dnt !== false) {\n writer.uint32(16).bool(message.dnt);\n }\n if (message.type !== \"\") {\n writer.uint32(26).string(message.type);\n }\n if (message.path !== \"\") {\n writer.uint32(34).string(message.path);\n }\n return writer;\n },\n decode(input, length) {\n const reader = input instanceof minimal_1.default.Reader ? input : minimal_1.default.Reader.create(input);\n let end = length === undefined ? reader.len : reader.pos + length;\n const message = createBaseTranslatableField();\n while (reader.pos < end) {\n const tag = reader.uint32();\n switch (tag >>> 3) {\n case 1:\n if (tag !== 10) {\n break;\n }\n message.value = reader.string();\n continue;\n case 2:\n if (tag !== 16) {\n break;\n }\n message.dnt = reader.bool();\n continue;\n case 3:\n if (tag !== 26) {\n break;\n }\n message.type = reader.string();\n continue;\n case 4:\n if (tag !== 34) {\n break;\n }\n message.path = reader.string();\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) {\n break;\n }\n reader.skipType(tag & 7);\n }\n return message;\n },\n fromJSON(object) {\n return {\n value: isSet(object.value) ? globalThis.String(object.value) : \"\",\n dnt: isSet(object.dnt) ? globalThis.Boolean(object.dnt) : false,\n type: isSet(object.type) ? globalThis.String(object.type) : \"\",\n path: isSet(object.path) ? globalThis.String(object.path) : \"\",\n };\n },\n toJSON(message) {\n const obj = {};\n if (message.value !== \"\") {\n obj.value = message.value;\n }\n if (message.dnt !== false) {\n obj.dnt = message.dnt;\n }\n if (message.type !== \"\") {\n obj.type = message.type;\n }\n if (message.path !== \"\") {\n obj.path = message.path;\n }\n return obj;\n },\n create(base) {\n return exports.TranslatableField.fromPartial(base ?? {});\n },\n fromPartial(object) {\n const message = createBaseTranslatableField();\n message.value = object.value ?? \"\";\n message.dnt = object.dnt ?? false;\n message.type = object.type ?? \"\";\n message.path = object.path ?? \"\";\n return message;\n },\n};\nfunction createBaseMetadata() {\n return { documentId: \"\", documentType: \"\", title: \"\", sourceLanguage: \"\", targetLanguage: \"\", targetLocales: [] };\n}\nexports.Metadata = {\n encode(message, writer = minimal_1.default.Writer.create()) {\n if (message.documentId !== \"\") {\n writer.uint32(10).string(message.documentId);\n }\n if (message.documentType !== \"\") {\n writer.uint32(18).string(message.documentType);\n }\n if (message.title !== \"\") {\n writer.uint32(26).string(message.title);\n }\n if (message.sourceLanguage !== \"\") {\n writer.uint32(34).string(message.sourceLanguage);\n }\n if (message.targetLanguage !== \"\") {\n writer.uint32(42).string(message.targetLanguage);\n }\n for (const v of message.targetLocales) {\n writer.uint32(50).string(v);\n }\n return writer;\n },\n decode(input, length) {\n const reader = input instanceof minimal_1.default.Reader ? input : minimal_1.default.Reader.create(input);\n let end = length === undefined ? reader.len : reader.pos + length;\n const message = createBaseMetadata();\n while (reader.pos < end) {\n const tag = reader.uint32();\n switch (tag >>> 3) {\n case 1:\n if (tag !== 10) {\n break;\n }\n message.documentId = reader.string();\n continue;\n case 2:\n if (tag !== 18) {\n break;\n }\n message.documentType = reader.string();\n continue;\n case 3:\n if (tag !== 26) {\n break;\n }\n message.title = reader.string();\n continue;\n case 4:\n if (tag !== 34) {\n break;\n }\n message.sourceLanguage = reader.string();\n continue;\n case 5:\n if (tag !== 42) {\n break;\n }\n message.targetLanguage = reader.string();\n continue;\n case 6:\n if (tag !== 50) {\n break;\n }\n message.targetLocales.push(reader.string());\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) {\n break;\n }\n reader.skipType(tag & 7);\n }\n return message;\n },\n fromJSON(object) {\n return {\n documentId: isSet(object.documentId) ? globalThis.String(object.documentId) : \"\",\n documentType: isSet(object.documentType) ? globalThis.String(object.documentType) : \"\",\n title: isSet(object.title) ? globalThis.String(object.title) : \"\",\n sourceLanguage: isSet(object.sourceLanguage) ? globalThis.String(object.sourceLanguage) : \"\",\n targetLanguage: isSet(object.targetLanguage) ? globalThis.String(object.targetLanguage) : \"\",\n targetLocales: globalThis.Array.isArray(object?.targetLocales)\n ? object.targetLocales.map((e) => globalThis.String(e))\n : [],\n };\n },\n toJSON(message) {\n const obj = {};\n if (message.documentId !== \"\") {\n obj.documentId = message.documentId;\n }\n if (message.documentType !== \"\") {\n obj.documentType = message.documentType;\n }\n if (message.title !== \"\") {\n obj.title = message.title;\n }\n if (message.sourceLanguage !== \"\") {\n obj.sourceLanguage = message.sourceLanguage;\n }\n if (message.targetLanguage !== \"\") {\n obj.targetLanguage = message.targetLanguage;\n }\n if (message.targetLocales?.length) {\n obj.targetLocales = message.targetLocales;\n }\n return obj;\n },\n create(base) {\n return exports.Metadata.fromPartial(base ?? {});\n },\n fromPartial(object) {\n const message = createBaseMetadata();\n message.documentId = object.documentId ?? \"\";\n message.documentType = object.documentType ?? \"\";\n message.title = object.title ?? \"\";\n message.sourceLanguage = object.sourceLanguage ?? \"\";\n message.targetLanguage = object.targetLanguage ?? \"\";\n message.targetLocales = object.targetLocales?.map((e) => e) || [];\n return message;\n },\n};\nfunction isObject(value) {\n return typeof value === \"object\" && value !== null;\n}\nfunction isSet(value) {\n return value !== null && value !== undefined;\n}\n","\"use strict\";\n// Code generated by protoc-gen-ts_proto. DO NOT EDIT.\n// versions:\n// protoc-gen-ts_proto v1.181.2\n// protoc v3.21.8\n// source: translation_response.proto\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.TranslatedDocument_FieldsEntry = exports.TranslatedDocument = exports.TranslationResponse = exports.protobufPackage = void 0;\n/* eslint-disable */\nconst minimal_1 = __importDefault(require(\"protobufjs/minimal\"));\nconst translation_request_1 = require(\"./translation_request\");\nexports.protobufPackage = \"hu.skawa.pagetranslate.server.model.protobuffers\";\nfunction createBaseTranslationResponse() {\n return { success: false, translatedDocuments: [], sourceLocale: \"\", error: \"\", requestId: \"\" };\n}\nexports.TranslationResponse = {\n encode(message, writer = minimal_1.default.Writer.create()) {\n if (message.success !== false) {\n writer.uint32(8).bool(message.success);\n }\n for (const v of message.translatedDocuments) {\n exports.TranslatedDocument.encode(v, writer.uint32(18).fork()).ldelim();\n }\n if (message.sourceLocale !== \"\") {\n writer.uint32(26).string(message.sourceLocale);\n }\n if (message.error !== \"\") {\n writer.uint32(34).string(message.error);\n }\n if (message.requestId !== \"\") {\n writer.uint32(42).string(message.requestId);\n }\n return writer;\n },\n decode(input, length) {\n const reader = input instanceof minimal_1.default.Reader ? input : minimal_1.default.Reader.create(input);\n let end = length === undefined ? reader.len : reader.pos + length;\n const message = createBaseTranslationResponse();\n while (reader.pos < end) {\n const tag = reader.uint32();\n switch (tag >>> 3) {\n case 1:\n if (tag !== 8) {\n break;\n }\n message.success = reader.bool();\n continue;\n case 2:\n if (tag !== 18) {\n break;\n }\n message.translatedDocuments.push(exports.TranslatedDocument.decode(reader, reader.uint32()));\n continue;\n case 3:\n if (tag !== 26) {\n break;\n }\n message.sourceLocale = reader.string();\n continue;\n case 4:\n if (tag !== 34) {\n break;\n }\n message.error = reader.string();\n continue;\n case 5:\n if (tag !== 42) {\n break;\n }\n message.requestId = reader.string();\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) {\n break;\n }\n reader.skipType(tag & 7);\n }\n return message;\n },\n fromJSON(object) {\n return {\n success: isSet(object.success) ? globalThis.Boolean(object.success) : false,\n translatedDocuments: globalThis.Array.isArray(object?.translatedDocuments)\n ? object.translatedDocuments.map((e) => exports.TranslatedDocument.fromJSON(e))\n : [],\n sourceLocale: isSet(object.sourceLocale) ? globalThis.String(object.sourceLocale) : \"\",\n error: isSet(object.error) ? globalThis.String(object.error) : \"\",\n requestId: isSet(object.requestId) ? globalThis.String(object.requestId) : \"\",\n };\n },\n toJSON(message) {\n const obj = {};\n if (message.success !== false) {\n obj.success = message.success;\n }\n if (message.translatedDocuments?.length) {\n obj.translatedDocuments = message.translatedDocuments.map((e) => exports.TranslatedDocument.toJSON(e));\n }\n if (message.sourceLocale !== \"\") {\n obj.sourceLocale = message.sourceLocale;\n }\n if (message.error !== \"\") {\n obj.error = message.error;\n }\n if (message.requestId !== \"\") {\n obj.requestId = message.requestId;\n }\n return obj;\n },\n create(base) {\n return exports.TranslationResponse.fromPartial(base ?? {});\n },\n fromPartial(object) {\n const message = createBaseTranslationResponse();\n message.success = object.success ?? false;\n message.translatedDocuments = object.translatedDocuments?.map((e) => exports.TranslatedDocument.fromPartial(e)) || [];\n message.sourceLocale = object.sourceLocale ?? \"\";\n message.error = object.error ?? \"\";\n message.requestId = object.requestId ?? \"\";\n return message;\n },\n};\nfunction createBaseTranslatedDocument() {\n return { body: \"\", title: \"\", slug: \"\", fields: {}, locale: \"\" };\n}\nexports.TranslatedDocument = {\n encode(message, writer = minimal_1.default.Writer.create()) {\n if (message.body !== \"\") {\n writer.uint32(10).string(message.body);\n }\n if (message.title !== \"\") {\n writer.uint32(18).string(message.title);\n }\n if (message.slug !== \"\") {\n writer.uint32(26).string(message.slug);\n }\n Object.entries(message.fields).forEach(([key, value]) => {\n exports.TranslatedDocument_FieldsEntry.encode({ key: key, value }, writer.uint32(34).fork()).ldelim();\n });\n if (message.locale !== \"\") {\n writer.uint32(42).string(message.locale);\n }\n return writer;\n },\n decode(input, length) {\n const reader = input instanceof minimal_1.default.Reader ? input : minimal_1.default.Reader.create(input);\n let end = length === undefined ? reader.len : reader.pos + length;\n const message = createBaseTranslatedDocument();\n while (reader.pos < end) {\n const tag = reader.uint32();\n switch (tag >>> 3) {\n case 1:\n if (tag !== 10) {\n break;\n }\n message.body = reader.string();\n continue;\n case 2:\n if (tag !== 18) {\n break;\n }\n message.title = reader.string();\n continue;\n case 3:\n if (tag !== 26) {\n break;\n }\n message.slug = reader.string();\n continue;\n case 4:\n if (tag !== 34) {\n break;\n }\n const entry4 = exports.TranslatedDocument_FieldsEntry.decode(reader, reader.uint32());\n if (entry4.value !== undefined) {\n message.fields[entry4.key] = entry4.value;\n }\n continue;\n case 5:\n if (tag !== 42) {\n break;\n }\n message.locale = reader.string();\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) {\n break;\n }\n reader.skipType(tag & 7);\n }\n return message;\n },\n fromJSON(object) {\n return {\n body: isSet(object.body) ? globalThis.String(object.body) : \"\",\n title: isSet(object.title) ? globalThis.String(object.title) : \"\",\n slug: isSet(object.slug) ? globalThis.String(object.slug) : \"\",\n fields: isObject(object.fields)\n ? Object.entries(object.fields).reduce((acc, [key, value]) => {\n acc[key] = translation_request_1.TranslatableField.fromJSON(value);\n return acc;\n }, {})\n : {},\n locale: isSet(object.locale) ? globalThis.String(object.locale) : \"\",\n };\n },\n toJSON(message) {\n const obj = {};\n if (message.body !== \"\") {\n obj.body = message.body;\n }\n if (message.title !== \"\") {\n obj.title = message.title;\n }\n if (message.slug !== \"\") {\n obj.slug = message.slug;\n }\n if (message.fields) {\n const entries = Object.entries(message.fields);\n if (entries.length > 0) {\n obj.fields = {};\n entries.forEach(([k, v]) => {\n obj.fields[k] = translation_request_1.TranslatableField.toJSON(v);\n });\n }\n }\n if (message.locale !== \"\") {\n obj.locale = message.locale;\n }\n return obj;\n },\n create(base) {\n return exports.TranslatedDocument.fromPartial(base ?? {});\n },\n fromPartial(object) {\n const message = createBaseTranslatedDocument();\n message.body = object.body ?? \"\";\n message.title = object.title ?? \"\";\n message.slug = object.slug ?? \"\";\n message.fields = Object.entries(object.fields ?? {}).reduce((acc, [key, value]) => {\n if (value !== undefined) {\n acc[key] = translation_request_1.TranslatableField.fromPartial(value);\n }\n return acc;\n }, {});\n message.locale = object.locale ?? \"\";\n return message;\n },\n};\nfunction createBaseTranslatedDocument_FieldsEntry() {\n return { key: \"\", value: undefined };\n}\nexports.TranslatedDocument_FieldsEntry = {\n encode(message, writer = minimal_1.default.Writer.create()) {\n if (message.key !== \"\") {\n writer.uint32(10).string(message.key);\n }\n if (message.value !== undefined) {\n translation_request_1.TranslatableField.encode(message.value, writer.uint32(18).fork()).ldelim();\n }\n return writer;\n },\n decode(input, length) {\n const reader = input instanceof minimal_1.default.Reader ? input : minimal_1.default.Reader.create(input);\n let end = length === undefined ? reader.len : reader.pos + length;\n const message = createBaseTranslatedDocument_FieldsEntry();\n while (reader.pos < end) {\n const tag = reader.uint32();\n switch (tag >>> 3) {\n case 1:\n if (tag !== 10) {\n break;\n }\n message.key = reader.string();\n continue;\n case 2:\n if (tag !== 18) {\n break;\n }\n message.value = translation_request_1.TranslatableField.decode(reader, reader.uint32());\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) {\n break;\n }\n reader.skipType(tag & 7);\n }\n return message;\n },\n fromJSON(object) {\n return {\n key: isSet(object.key) ? globalThis.String(object.key) : \"\",\n value: isSet(object.value) ? translation_request_1.TranslatableField.fromJSON(object.value) : undefined,\n };\n },\n toJSON(message) {\n const obj = {};\n if (message.key !== \"\") {\n obj.key = message.key;\n }\n if (message.value !== undefined) {\n obj.value = translation_request_1.TranslatableField.toJSON(message.value);\n }\n return obj;\n },\n create(base) {\n return exports.TranslatedDocument_FieldsEntry.fromPartial(base ?? {});\n },\n fromPartial(object) {\n const message = createBaseTranslatedDocument_FieldsEntry();\n message.key = object.key ?? \"\";\n message.value = (object.value !== undefined && object.value !== null)\n ? translation_request_1.TranslatableField.fromPartial(object.value)\n : undefined;\n return message;\n },\n};\nfunction isObject(value) {\n return typeof value === \"object\" && value !== null;\n}\nfunction isSet(value) {\n return value !== null && value !== undefined;\n}\n","\"use strict\";\r\nmodule.exports = asPromise;\r\n\r\n/**\r\n * Callback as used by {@link util.asPromise}.\r\n * @typedef asPromiseCallback\r\n * @type {function}\r\n * @param {Error|null} error Error, if any\r\n * @param {...*} params Additional arguments\r\n * @returns {undefined}\r\n */\r\n\r\n/**\r\n * Returns a promise from a node-style callback function.\r\n * @memberof util\r\n * @param {asPromiseCallback} fn Function to call\r\n * @param {*} ctx Function context\r\n * @param {...*} params Function arguments\r\n * @returns {Promise<*>} Promisified function\r\n */\r\nfunction asPromise(fn, ctx/*, varargs */) {\r\n var params = new Array(arguments.length - 1),\r\n offset = 0,\r\n index = 2,\r\n pending = true;\r\n while (index < arguments.length)\r\n params[offset++] = arguments[index++];\r\n return new Promise(function executor(resolve, reject) {\r\n params[offset] = function callback(err/*, varargs */) {\r\n if (pending) {\r\n pending = false;\r\n if (err)\r\n reject(err);\r\n else {\r\n var params = new Array(arguments.length - 1),\r\n offset = 0;\r\n while (offset < params.length)\r\n params[offset++] = arguments[offset];\r\n resolve.apply(null, params);\r\n }\r\n }\r\n };\r\n try {\r\n fn.apply(ctx || null, params);\r\n } catch (err) {\r\n if (pending) {\r\n pending = false;\r\n reject(err);\r\n }\r\n }\r\n });\r\n}\r\n","\"use strict\";\r\n\r\n/**\r\n * A minimal base64 implementation for number arrays.\r\n * @memberof util\r\n * @namespace\r\n */\r\nvar base64 = exports;\r\n\r\n/**\r\n * Calculates the byte length of a base64 encoded string.\r\n * @param {string} string Base64 encoded string\r\n * @returns {number} Byte length\r\n */\r\nbase64.length = function length(string) {\r\n var p = string.length;\r\n if (!p)\r\n return 0;\r\n var n = 0;\r\n while (--p % 4 > 1 && string.charAt(p) === \"=\")\r\n ++n;\r\n return Math.ceil(string.length * 3) / 4 - n;\r\n};\r\n\r\n// Base64 encoding table\r\nvar b64 = new Array(64);\r\n\r\n// Base64 decoding table\r\nvar s64 = new Array(123);\r\n\r\n// 65..90, 97..122, 48..57, 43, 47\r\nfor (var i = 0; i < 64;)\r\n s64[b64[i] = i < 26 ? i + 65 : i < 52 ? i + 71 : i < 62 ? i - 4 : i - 59 | 43] = i++;\r\n\r\n/**\r\n * Encodes a buffer to a base64 encoded string.\r\n * @param {Uint8Array} buffer Source buffer\r\n * @param {number} start Source start\r\n * @param {number} end Source end\r\n * @returns {string} Base64 encoded string\r\n */\r\nbase64.encode = function encode(buffer, start, end) {\r\n var parts = null,\r\n chunk = [];\r\n var i = 0, // output index\r\n j = 0, // goto index\r\n t; // temporary\r\n while (start < end) {\r\n var b = buffer[start++];\r\n switch (j) {\r\n case 0:\r\n chunk[i++] = b64[b >> 2];\r\n t = (b & 3) << 4;\r\n j = 1;\r\n break;\r\n case 1:\r\n chunk[i++] = b64[t | b >> 4];\r\n t = (b & 15) << 2;\r\n j = 2;\r\n break;\r\n case 2:\r\n chunk[i++] = b64[t | b >> 6];\r\n chunk[i++] = b64[b & 63];\r\n j = 0;\r\n break;\r\n }\r\n if (i > 8191) {\r\n (parts || (parts = [])).push(String.fromCharCode.apply(String, chunk));\r\n i = 0;\r\n }\r\n }\r\n if (j) {\r\n chunk[i++] = b64[t];\r\n chunk[i++] = 61;\r\n if (j === 1)\r\n chunk[i++] = 61;\r\n }\r\n if (parts) {\r\n if (i)\r\n parts.push(String.fromCharCode.apply(String, chunk.slice(0, i)));\r\n return parts.join(\"\");\r\n }\r\n return String.fromCharCode.apply(String, chunk.slice(0, i));\r\n};\r\n\r\nvar invalidEncoding = \"invalid encoding\";\r\n\r\n/**\r\n * Decodes a base64 encoded string to a buffer.\r\n * @param {string} string Source string\r\n * @param {Uint8Array} buffer Destination buffer\r\n * @param {number} offset Destination offset\r\n * @returns {number} Number of bytes written\r\n * @throws {Error} If encoding is invalid\r\n */\r\nbase64.decode = function decode(string, buffer, offset) {\r\n var start = offset;\r\n var j = 0, // goto index\r\n t; // temporary\r\n for (var i = 0; i < string.length;) {\r\n var c = string.charCodeAt(i++);\r\n if (c === 61 && j > 1)\r\n break;\r\n if ((c = s64[c]) === undefined)\r\n throw Error(invalidEncoding);\r\n switch (j) {\r\n case 0:\r\n t = c;\r\n j = 1;\r\n break;\r\n case 1:\r\n buffer[offset++] = t << 2 | (c & 48) >> 4;\r\n t = c;\r\n j = 2;\r\n break;\r\n case 2:\r\n buffer[offset++] = (t & 15) << 4 | (c & 60) >> 2;\r\n t = c;\r\n j = 3;\r\n break;\r\n case 3:\r\n buffer[offset++] = (t & 3) << 6 | c;\r\n j = 0;\r\n break;\r\n }\r\n }\r\n if (j === 1)\r\n throw Error(invalidEncoding);\r\n return offset - start;\r\n};\r\n\r\n/**\r\n * Tests if the specified string appears to be base64 encoded.\r\n * @param {string} string String to test\r\n * @returns {boolean} `true` if probably base64 encoded, otherwise false\r\n */\r\nbase64.test = function test(string) {\r\n return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(string);\r\n};\r\n","\"use strict\";\r\nmodule.exports = EventEmitter;\r\n\r\n/**\r\n * Constructs a new event emitter instance.\r\n * @classdesc A minimal event emitter.\r\n * @memberof util\r\n * @constructor\r\n */\r\nfunction EventEmitter() {\r\n\r\n /**\r\n * Registered listeners.\r\n * @type {Object.<string,*>}\r\n * @private\r\n */\r\n this._listeners = {};\r\n}\r\n\r\n/**\r\n * Registers an event listener.\r\n * @param {string} evt Event name\r\n * @param {function} fn Listener\r\n * @param {*} [ctx] Listener context\r\n * @returns {util.EventEmitter} `this`\r\n */\r\nEventEmitter.prototype.on = function on(evt, fn, ctx) {\r\n (this._listeners[evt] || (this._listeners[evt] = [])).push({\r\n fn : fn,\r\n ctx : ctx || this\r\n });\r\n return this;\r\n};\r\n\r\n/**\r\n * Removes an event listener or any matching listeners if arguments are omitted.\r\n * @param {string} [evt] Event name. Removes all listeners if omitted.\r\n * @param {function} [fn] Listener to remove. Removes all listeners of `evt` if omitted.\r\n * @returns {util.EventEmitter} `this`\r\n */\r\nEventEmitter.prototype.off = function off(evt, fn) {\r\n if (evt === undefined)\r\n this._listeners = {};\r\n else {\r\n if (fn === undefined)\r\n this._listeners[evt] = [];\r\n else {\r\n var listeners = this._listeners[evt];\r\n for (var i = 0; i < listeners.length;)\r\n if (listeners[i].fn === fn)\r\n listeners.splice(i, 1);\r\n else\r\n ++i;\r\n }\r\n }\r\n return this;\r\n};\r\n\r\n/**\r\n * Emits an event by calling its listeners with the specified arguments.\r\n * @param {string} evt Event name\r\n * @param {...*} args Arguments\r\n * @returns {util.EventEmitter} `this`\r\n */\r\nEventEmitter.prototype.emit = function emit(evt) {\r\n var listeners = this._listeners[evt];\r\n if (listeners) {\r\n var args = [],\r\n i = 1;\r\n for (; i < arguments.length;)\r\n args.push(arguments[i++]);\r\n for (i = 0; i < listeners.length;)\r\n listeners[i].fn.apply(listeners[i++].ctx, args);\r\n }\r\n return this;\r\n};\r\n","\"use strict\";\r\n\r\nmodule.exports = factory(factory);\r\n\r\n/**\r\n * Reads / writes floats / doubles from / to buffers.\r\n * @name util.float\r\n * @namespace\r\n */\r\n\r\n/**\r\n * Writes a 32 bit float to a buffer using little endian byte order.\r\n * @name util.float.writeFloatLE\r\n * @function\r\n * @param {number} val Value to write\r\n * @param {Uint8Array} buf Target buffer\r\n * @param {number} pos Target buffer offset\r\n * @returns {undefined}\r\n */\r\n\r\n/**\r\n * Writes a 32 bit float to a buffer using big endian byte order.\r\n * @name util.float.writeFloatBE\r\n * @function\r\n * @param {number} val Value to write\r\n * @param {Uint8Array} buf Target buffer\r\n * @param {number} pos Target buffer offset\r\n * @returns {undefined}\r\n */\r\n\r\n/**\r\n * Reads a 32 bit float from a buffer using little endian byte order.\r\n * @name util.float.readFloatLE\r\n * @function\r\n * @param {Uint8Array} buf Source buffer\r\n * @param {number} pos Source buffer offset\r\n * @returns {number} Value read\r\n */\r\n\r\n/**\r\n * Reads a 32 bit float from a buffer using big endian byte order.\r\n * @name util.float.readFloatBE\r\n * @function\r\n * @param {Uint8Array} buf Source buffer\r\n * @param {number} pos Source buffer offset\r\n * @returns {number} Value read\r\n */\r\n\r\n/**\r\n * Writes a 64 bit double to a buffer using little endian byte order.\r\n * @name util.float.writeDoubleLE\r\n * @function\r\n * @param {number} val Value to write\r\n * @param {Uint8Array} buf Target buffer\r\n * @param {number} pos Target buffer offset\r\n * @returns {undefined}\r\n */\r\n\r\n/**\r\n * Writes a 64 bit double to a buffer using big endian byte order.\r\n * @name util.float.writeDoubleBE\r\n * @function\r\n * @param {number} val Value to write\r\n * @param {Uint8Array} buf Target buffer\r\n * @param {number} pos Target buffer offset\r\n * @returns {undefined}\r\n */\r\n\r\n/**\r\n * Reads a 64 bit double from a buffer using little endian byte order.\r\n * @name util.float.readDoubleLE\r\n * @function\r\n * @param {Uint8Array} buf Source buffer\r\n * @param {number} pos Source buffer offset\r\n * @returns {number} Value read\r\n */\r\n\r\n/**\r\n * Reads a 64 bit double from a buffer using big endian byte order.\r\n * @name util.float.readDoubleBE\r\n * @function\r\n * @param {Uint8Array} buf Source buffer\r\n * @param {number} pos Source buffer offset\r\n * @returns {number} Value read\r\n */\r\n\r\n// Factory function for the purpose of node-based testing in modified global environments\r\nfunction factory(exports) {\r\n\r\n // float: typed array\r\n if (typeof Float32Array !== \"undefined\") (function() {\r\n\r\n var f32 = new Float32Array([ -0 ]),\r\n f8b = new Uint8Array(f32.buffer),\r\n le = f8b[3] === 128;\r\n\r\n function writeFloat_f32_cpy(val, buf, pos) {\r\n f32[0] = val;\r\n buf[pos ] = f8b[0];\r\n buf[pos + 1] = f8b[1];\r\n buf[pos + 2] = f8b[2];\r\n buf[pos + 3] = f8b[3];\r\n }\r\n\r\n function writeFloat_f32_rev(val, buf, pos) {\r\n f32[0] = val;\r\n buf[pos ] = f8b[3];\r\n buf[pos + 1] = f8b[2];\r\n buf[pos + 2] = f8b[1];\r\n buf[pos + 3] = f8b[0];\r\n }\r\n\r\n /* istanbul ignore next */\r\n exports.writeFloatLE = le ? writeFloat_f32_cpy : writeFloat_f32_rev;\r\n /* istanbul ignore next */\r\n exports.writeFloatBE = le ? writeFloat_f32_rev : writeFloat_f32_cpy;\r\n\r\n function readFloat_f32_cpy(buf, pos) {\r\n f8b[0] = buf[pos ];\r\n f8b[1] = buf[pos + 1];\r\n f8b[2] = buf[pos + 2];\r\n f8b[3] = buf[pos + 3];\r\n return f32[0];\r\n }\r\n\r\n function readFloat_f32_rev(buf, pos) {\r\n f8b[3] = buf[pos ];\r\n f8b[2] = buf[pos + 1];\r\n f8b[1] = buf[pos + 2];\r\n f8b[0] = buf[pos + 3];\r\n return f32[0];\r\n }\r\n\r\n /* istanbul ignore next */\r\n exports.readFloatLE = le ? readFloat_f32_cpy : readFloat_f32_rev;\r\n /* istanbul ignore next */\r\n exports.readFloatBE = le ? readFloat_f32_rev : readFloat_f32_cpy;\r\n\r\n // float: ieee754\r\n })(); else (function() {\r\n\r\n function writeFloat_ieee754(writeUint, val, buf, pos) {\r\n var sign = val < 0 ? 1 : 0;\r\n if (sign)\r\n val = -val;\r\n if (val === 0)\r\n writeUint(1 / val > 0 ? /* positive */ 0 : /* negative 0 */ 2147483648, buf, pos);\r\n else if (isNaN(val))\r\n writeUint(2143289344, buf, pos);\r\n else if (val > 3.4028234663852886e+38) // +-Infinity\r\n writeUint((sign << 31 | 2139095040) >>> 0, buf, pos);\r\n else if (val < 1.1754943508222875e-38) // denormal\r\n writeUint((sign << 31 | Math.round(val / 1.401298464324817e-45)) >>> 0, buf, pos);\r\n else {\r\n var exponent = Math.floor(Math.log(val) / Math.LN2),\r\n mantissa = Math.round(val * Math.pow(2, -exponent) * 8388608) & 8388607;\r\n writeUint((sign << 31 | exponent + 127 << 23 | mantissa) >>> 0, buf, pos);\r\n }\r\n }\r\n\r\n exports.writeFloatLE = writeFloat_ieee754.bind(null, writeUintLE);\r\n exports.writeFloatBE = writeFloat_ieee754.bind(null, writeUintBE);\r\n\r\n function readFloat_ieee754(readUint, buf, pos) {\r\n var uint = readUint(buf, pos),\r\n sign = (uint >> 31) * 2 + 1,\r\n exponent = uint >>> 23 & 255,\r\n mantissa = uint & 8388607;\r\n return exponent === 255\r\n ? mantissa\r\n ? NaN\r\n : sign * Infinity\r\n : exponent === 0 // denormal\r\n ? sign * 1.401298464324817e-45 * mantissa\r\n : sign * Math.pow(2, exponent - 150) * (mantissa + 8388608);\r\n }\r\n\r\n exports.readFloatLE = readFloat_ieee754.bind(null, readUintLE);\r\n exports.readFloatBE = readFloat_ieee754.bind(null, readUintBE);\r\n\r\n })();\r\n\r\n // double: typed array\r\n if (typeof Float64Array !== \"undefined\") (function() {\r\n\r\n var f64 = new Float64Array([-0]),\r\n f8b = new Uint8Array(f64.buffer),\r\n le = f8b[7] === 128;\r\n\r\n function writeDouble_f64_cpy(val, buf, pos) {\r\n f64[0] = val;\r\n buf[pos ] = f8b[0];\r\n buf[pos + 1] = f8b[1];\r\n buf[pos + 2] = f8b[2];\r\n buf[pos + 3] = f8b[3];\r\n buf[pos + 4] = f8b[4];\r\n buf[pos + 5] = f8b[5];\r\n buf[pos + 6] = f8b[6];\r\n buf[pos + 7] = f8b[7];\r\n }\r\n\r\n function writeDouble_f64_rev(val, buf, pos) {\r\n f64[0] = val;\r\n buf[pos ] = f8b[7];\r\n buf[pos + 1] = f8b[6];\r\n buf[pos + 2] = f8b[5];\r\n buf[pos + 3] = f8b[4];\r\n buf[pos + 4] = f8b[3];\r\n buf[pos + 5] = f8b[2];\r\n buf[pos + 6] = f8b[1];\r\n buf[pos + 7] = f8b[0];\r\n }\r\n\r\n /* istanbul ignore next */\r\n exports.writeDoubleLE = le ? writeDouble_f64_cpy : writeDouble_f64_rev;\r\n /* istanbul ignore next */\r\n exports.writeDoubleBE = le ? writeDouble_f64_rev : writeDouble_f64_cpy;\r\n\r\n function readDouble_f64_cpy(buf, pos) {\r\n f8b[0] = buf[pos ];\r\n f8b[1] = buf[pos + 1];\r\n f8b[2] = buf[pos + 2];\r\n f8b[3] = buf[pos + 3];\r\n f8b[4] = buf[pos + 4];\r\n f8b[5] = buf[pos + 5];\r\n f8b[6] = buf[pos + 6];\r\n f8b[7] = buf[pos + 7];\r\n return f64[0];\r\n }\r\n\r\n function readDouble_f64_rev(buf, pos) {\r\n f8b[7] = buf[pos ];\r\n f8b[6] = buf[pos + 1];\r\n f8b[5] = buf[pos + 2];\r\n f8b[4] = buf[pos + 3];\r\n f8b[3] = buf[pos + 4];\r\n f8b[2] = buf[pos + 5];\r\n f8b[1] = buf[pos + 6];\r\n f8b[0] = buf[pos + 7];\r\n return f64[0];\r\n }\r\n\r\n /* istanbul ignore next */\r\n exports.readDoubleLE = le ? readDouble_f64_cpy : readDouble_f64_rev;\r\n /* istanbul ignore next */\r\n exports.readDoubleBE = le ? readDouble_f64_rev : readDouble_f64_cpy;\r\n\r\n // double: ieee754\r\n })(); else (function() {\r\n\r\n function writeDouble_ieee754(writeUint, off0, off1, val, buf, pos) {\r\n var sign = val < 0 ? 1 : 0;\r\n if (sign)\r\n val = -val;\r\n if (val === 0) {\r\n writeUint(0, buf, pos + off0);\r\n writeUint(1 / val > 0 ? /* positive */ 0 : /* negative 0 */ 2147483648, buf, pos + off1);\r\n } else if (isNaN(val)) {\r\n writeUint(0, buf, pos + off0);\r\n writeUint(2146959360, buf, pos + off1);\r\n } else if (val > 1.7976931348623157e+308) { // +-Infinity\r\n writeUint(0, buf, pos + off0);\r\n writeUint((sign << 31 | 2146435072) >>> 0, buf, pos + off1);\r\n } else {\r\n var mantissa;\r\n if (val < 2.2250738585072014e-308) { // denormal\r\n mantissa = val / 5e-324;\r\n writeUint(mantissa >>> 0, buf, pos + off0);\r\n writeUint((sign << 31 | mantissa / 4294967296) >>> 0, buf, pos + off1);\r\n } else {\r\n var exponent = Math.floor(Math.log(val) / Math.LN2);\r\n if (exponent === 1024)\r\n exponent = 1023;\r\n mantissa = val * Math.pow(2, -exponent);\r\n writeUint(mantissa * 4503599627370496 >>> 0, buf, pos + off0);\r\n writeUint((sign << 31 | exponent + 1023 << 20 | mantissa * 1048576 & 1048575) >>> 0, buf, pos + off1);\r\n }\r\n }\r\n }\r\n\r\n exports.writeDoubleLE = writeDouble_ieee754.bind(null, writeUintLE, 0, 4);\r\n exports.writeDoubleBE = writeDouble_ieee754.bind(null, writeUintBE, 4, 0);\r\n\r\n function readDouble_ieee754(readUint, off0, off1, buf, pos) {\r\n var lo = readUint(buf, pos + off0),\r\n hi = readUint(buf, pos + off1);\r\n var sign = (hi >> 31) * 2 + 1,\r\n exponent = hi >>> 20 & 2047,\r\n mantissa = 4294967296 * (hi & 1048575) + lo;\r\n return exponent === 2047\r\n ? mantissa\r\n ? NaN\r\n : sign * Infinity\r\n : exponent === 0 // denormal\r\n ? sign * 5e-324 * mantissa\r\n : sign * Math.pow(2, exponent - 1075) * (mantissa + 4503599627370496);\r\n }\r\n\r\n exports.readDoubleLE = readDouble_ieee754.bind(null, readUintLE, 0, 4);\r\n exports.readDoubleBE = readDouble_ieee754.bind(null, readUintBE, 4, 0);\r\n\r\n })();\r\n\r\n return exports;\r\n}\r\n\r\n// uint helpers\r\n\r\nfunction writeUintLE(val, buf, pos) {\r\n buf[pos ] = val & 255;\r\n buf[pos + 1] = val >>> 8 & 255;\r\n buf[pos + 2] = val >>> 16 & 255;\r\n buf[pos + 3] = val >>> 24;\r\n}\r\n\r\nfunction writeUintBE(val, buf, pos) {\r\n buf[pos ] = val >>> 24;\r\n buf[pos + 1] = val >>> 16 & 255;\r\n buf[pos + 2] = val >>> 8 & 255;\r\n buf[pos + 3] = val & 255;\r\n}\r\n\r\nfunction readUintLE(buf, pos) {\r\n return (buf[pos ]\r\n | buf[pos + 1] << 8\r\n | buf[pos + 2] << 16\r\n | buf[pos + 3] << 24) >>> 0;\r\n}\r\n\r\nfunction readUintBE(buf, pos) {\r\n return (buf[pos ] << 24\r\n | buf[pos + 1] << 16\r\n | buf[pos + 2] << 8\r\n | buf[pos + 3]) >>> 0;\r\n}\r\n","\"use strict\";\r\nmodule.exports = inquire;\r\n\r\n/**\r\n * Requires a module only if available.\r\n * @memberof util\r\n * @param {string} moduleName Module to require\r\n * @returns {?Object} Required module if available and not empty, otherwise `null`\r\n */\r\nfunction inquire(moduleName) {\r\n try {\r\n var mod = eval(\"quire\".replace(/^/,\"re\"))(moduleName); // eslint-disable-line no-eval\r\n if (mod && (mod.length || Object.keys(mod).length))\r\n return mod;\r\n } catch (e) {} // eslint-disable-line no-empty\r\n return null;\r\n}\r\n","\"use strict\";\r\nmodule.exports = pool;\r\n\r\n/**\r\n * An allocator as used by {@link util.pool}.\r\n * @typedef PoolAllocator\r\n * @type {function}\r\n * @param {number} size Buffer size\r\n * @returns {Uint8Array} Buffer\r\n */\r\n\r\n/**\r\n * A slicer as used by {@link util.pool}.\r\n * @typedef PoolSlicer\r\n * @type {function}\r\n * @param {number} start Start offset\r\n * @param {number} end End offset\r\n * @returns {Uint8Array} Buffer slice\r\n * @this {Uint8Array}\r\n */\r\n\r\n/**\r\n * A general purpose buffer pool.\r\n * @memberof util\r\n * @function\r\n * @param {PoolAllocator} alloc Allocator\r\n * @param {PoolSlicer} slice Slicer\r\n * @param {number} [size=8192] Slab size\r\n * @returns {PoolAllocator} Pooled allocator\r\n */\r\nfunction pool(alloc, slice, size) {\r\n var SIZE = size || 8192;\r\n var MAX = SIZE >>> 1;\r\n var slab = null;\r\n var offset = SIZE;\r\n return function pool_alloc(size) {\r\n if (size < 1 || size > MAX)\r\n return alloc(size);\r\n if (offset + size > SIZE) {\r\n slab = alloc(SIZE);\r\n offset = 0;\r\n }\r\n var buf = slice.call(slab, offset, offset += size);\r\n if (offset & 7) // align to 32 bit\r\n offset = (offset | 7) + 1;\r\n return buf;\r\n };\r\n}\r\n","\"use strict\";\r\n\r\n/**\r\n * A minimal UTF8 implementation for number arrays.\r\n * @memberof util\r\n * @namespace\r\n */\r\nvar utf8 = exports;\r\n\r\n/**\r\n * Calculates the UTF8 byte length of a string.\r\n * @param {string} string String\r\n * @returns {number} Byte length\r\n */\r\nutf8.length = function utf8_length(string) {\r\n var len = 0,\r\n c = 0;\r\n for (var i = 0; i < string.length; ++i) {\r\n c = string.charCodeAt(i);\r\n if (c < 128)\r\n len += 1;\r\n else if (c < 2048)\r\n len += 2;\r\n else if ((c & 0xFC00) === 0xD800 && (string.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {\r\n ++i;\r\n len += 4;\r\n } else\r\n len += 3;\r\n }\r\n return len;\r\n};\r\n\r\n/**\r\n * Reads UTF8 bytes as a string.\r\n * @param {Uint8Array} buffer Source buffer\r\n * @param {number} start Source start\r\n * @param {number} end Source end\r\n * @returns {string} String read\r\n */\r\nutf8.read = function utf8_read(buffer, start, end) {\r\n var len = end - start;\r\n if (len < 1)\r\n return \"\";\r\n var parts = null,\r\n chunk = [],\r\n i = 0, // char offset\r\n t; // temporary\r\n while (start < end) {\r\n t = buffer[start++];\r\n if (t < 128)\r\n chunk[i++] = t;\r\n else if (t > 191 && t < 224)\r\n chunk[i++] = (t & 31) << 6 | buffer[start++] & 63;\r\n else if (t > 239 && t < 365) {\r\n t = ((t & 7) << 18 | (buffer[start++] & 63) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63) - 0x10000;\r\n chunk[i++] = 0xD800 + (t >> 10);\r\n chunk[i++] = 0xDC00 + (t & 1023);\r\n } else\r\n chunk[i++] = (t & 15) << 12 | (buffer[start++] & 63) << 6 | buffer[start++] & 63;\r\n if (i > 8191) {\r\n (parts || (parts = [])).push(String.fromCharCode.apply(String, chunk));\r\n i = 0;\r\n }\r\n }\r\n if (parts) {\r\n if (i)\r\n parts.push(String.fromCharCode.apply(String, chunk.slice(0, i)));\r\n return parts.join(\"\");\r\n }\r\n return String.fromCharCode.apply(String, chunk.slice(0, i));\r\n};\r\n\r\n/**\r\n * Writes a string as UTF8 bytes.\r\n * @param {string} string Source string\r\n * @param {Uint8Array} buffer Destination buffer\r\n * @param {number} offset Destination offset\r\n * @returns {number} Bytes written\r\n */\r\nutf8.write = function utf8_write(string, buffer, offset) {\r\n var start = offset,\r\n c1, // character 1\r\n c2; // character 2\r\n for (var i = 0; i < string.length; ++i) {\r\n c1 = string.charCodeAt(i);\r\n if (c1 < 128) {\r\n buffer[offset++] = c1;\r\n } else if (c1 < 2048) {\r\n buffer[offset++] = c1 >> 6 | 192;\r\n buffer[offset++] = c1 & 63 | 128;\r\n } else if ((c1 & 0xFC00) === 0xD800 && ((c2 = string.charCodeAt(i + 1)) & 0xFC00) === 0xDC00) {\r\n c1 = 0x10000 + ((c1 & 0x03FF) << 10) + (c2 & 0x03FF);\r\n ++i;\r\n buffer[offset++] = c1 >> 18 | 240;\r\n buffer[offset++] = c1 >> 12 & 63 | 128;\r\n buffer[offset++] = c1 >> 6 & 63 | 128;\r\n buffer[offset++] = c1 & 63 | 128;\r\n } else {\r\n buffer[offset++] = c1 >> 12 | 224;\r\n buffer[offset++] = c1 >> 6 & 63 | 128;\r\n buffer[offset++] = c1 & 63 | 128;\r\n }\r\n }\r\n return offset - start;\r\n};\r\n","// minimal library entry point.\n\n\"use strict\";\nmodule.exports = require(\"./src/index-minimal\");\n","\"use strict\";\nvar protobuf = exports;\n\n/**\n * Build type, one of `\"full\"`, `\"light\"` or `\"minimal\"`.\n * @name build\n * @type {string}\n * @const\n */\nprotobuf.build = \"minimal\";\n\n// Serialization\nprotobuf.Writer = require(\"./writer\");\nprotobuf.BufferWriter = require(\"./writer_buffer\");\nprotobuf.Reader = require(\"./reader\");\nprotobuf.BufferReader = require(\"./reader_buffer\");\n\n// Utility\nprotobuf.util = require(\"./util/minimal\");\nprotobuf.rpc = require(\"./rpc\");\nprotobuf.roots = require(\"./roots\");\nprotobuf.configure = configure;\n\n/* istanbul ignore next */\n/**\n * Reconfigures the library according to the environment.\n * @returns {undefined}\n */\nfunction configure() {\n protobuf.util._configure();\n protobuf.Writer._configure(protobuf.BufferWriter);\n protobuf.Reader._configure(protobuf.BufferReader);\n}\n\n// Set up buffer utility according to the environment\nconfigure();\n","\"use strict\";\nmodule.exports = Reader;\n\nvar util = require(\"./util/minimal\");\n\nvar BufferReader; // cyclic\n\nvar LongBits = util.LongBits,\n utf8 = util.utf8;\n\n/* istanbul ignore next */\nfunction indexOutOfRange(reader, writeLength) {\n return RangeError(\"index out of range: \" + reader.pos + \" + \" + (writeLength || 1) + \" > \" + reader.len);\n}\n\n/**\n * Constructs a new reader instance using the specified buffer.\n * @classdesc Wire format reader using `Uint8Array` if available, otherwise `Array`.\n * @constructor\n * @param {Uint8Array} buffer Buffer to read from\n */\nfunction Reader(buffer) {\n\n /**\n * Read buffer.\n * @type {Uint8Array}\n */\n this.buf = buffer;\n\n /**\n * Read buffer position.\n * @type {number}\n */\n this.pos = 0;\n\n /**\n * Read buffer length.\n * @type {number}\n */\n this.len = buffer.length;\n}\n\nvar create_array = typeof Uint8Array !== \"undefined\"\n ? function create_typed_array(buffer) {\n if (buffer instanceof Uint8Array || Array.isArray(buffer))\n return new Reader(buffer);\n throw Error(\"illegal buffer\");\n }\n /* istanbul ignore next */\n : function create_array(buffer) {\n if (Array.isArray(buffer))\n return new Reader(buffer);\n throw Error(\"illegal buffer\");\n };\n\nvar create = function create() {\n return util.Buffer\n ? function create_buffer_setup(buffer) {\n return (Reader.create = function create_buffer(buffer) {\n return util.Buffer.isBuffer(buffer)\n ? new BufferReader(buffer)\n /* istanbul ignore next */\n : create_array(buffer);\n })(buffer);\n }\n /* istanbul ignore next */\n : create_array;\n};\n\n/**\n * Creates a new reader using the specified buffer.\n * @function\n * @param {Uint8Array|Buffer} buffer Buffer to read from\n * @returns {Reader|BufferReader} A {@link BufferReader} if `buffer` is a Buffer, otherwise a {@link Reader}\n * @throws {Error} If `buffer` is not a valid buffer\n */\nReader.create = create();\n\nReader.prototype._slice = util.Array.prototype.subarray || /* istanbul ignore next */ util.Array.prototype.slice;\n\n/**\n * Reads a varint as an unsigned 32 bit value.\n * @function\n * @returns {number} Value read\n */\nReader.prototype.uint32 = (function read_uint32_setup() {\n var value = 4294967295; // optimizer type-hint, tends to deopt otherwise (?!)\n return function read_uint32() {\n value = ( this.buf[this.pos] & 127 ) >>> 0; if (this.buf[this.pos++] < 128) return value;\n value = (value | (this.buf[this.pos] & 127) << 7) >>> 0; if (this.buf[this.pos++] < 128) return value;\n value = (value | (this.buf[this.pos] & 127) << 14) >>> 0; if (this.buf[this.pos++] < 128) return value;\n value = (value | (this.buf[this.pos] & 127) << 21) >>> 0; if (this.buf[this.pos++] < 128) return value;\n value = (value | (this.buf[this.pos] & 15) << 28) >>> 0; if (this.buf[this.pos++] < 128) return value;\n\n /* istanbul ignore if */\n if ((this.pos += 5) > this.len) {\n this.pos = this.len;\n throw indexOutOfRange(this, 10);\n }\n return value;\n };\n})();\n\n/**\n * Reads a varint as a signed 32 bit value.\n * @returns {number} Value read\n */\nReader.prototype.int32 = function read_int32() {\n return this.uint32() | 0;\n};\n\n/**\n * Reads a zig-zag encoded varint as a signed 32 bit value.\n * @returns {number} Value read\n */\nReader.prototype.sint32 = function read_sint32() {\n var value = this.uint32();\n return value >>> 1 ^ -(value & 1) | 0;\n};\n\n/* eslint-disable no-invalid-this */\n\nfunction readLongVarint() {\n // tends to deopt with local vars for octet etc.\n var bits = new LongBits(0, 0);\n var i = 0;\n if (this.len - this.pos > 4) { // fast route (lo)\n for (; i < 4; ++i) {\n // 1st..4th\n bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0;\n if (this.buf[this.pos++] < 128)\n return bits;\n }\n // 5th\n bits.lo = (bits.lo | (this.buf[this.pos] & 127) << 28) >>> 0;\n bits.hi = (bits.hi | (this.buf[this.pos] & 127) >> 4) >>> 0;\n if (this.buf[this.pos++] < 128)\n return bits;\n i = 0;\n } else {\n for (; i < 3; ++i) {\n /* istanbul ignore if */\n if (this.pos >= this.len)\n throw indexOutOfRange(this);\n // 1st..3th\n bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0;\n if (this.buf[this.pos++] < 128)\n return bits;\n }\n // 4th\n bits.lo = (bits.lo | (this.buf[this.pos++] & 127) << i * 7) >>> 0;\n return bits;\n }\n if (this.len - this.pos > 4) { // fast route (hi)\n for (; i < 5; ++i) {\n // 6th..10th\n bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0;\n if (this.buf[this.pos++] < 128)\n return bits;\n }\n } else {\n for (; i < 5; ++i) {\n /* istanbul ignore if */\n if (this.pos >= this.len)\n throw indexOutOfRange(this);\n // 6th..10th\n bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0;\n if (this.buf[this.pos++] < 128)\n return bits;\n }\n }\n /* istanbul ignore next */\n throw Error(\"invalid varint encoding\");\n}\n\n/* eslint-enable no-invalid-this */\n\n/**\n * Reads a varint as a signed 64 bit value.\n * @name Reader#int64\n * @function\n * @returns {Long} Value read\n */\n\n/**\n * Reads a varint as an unsigned 64 bit value.\n * @name Reader#uint64\n * @function\n * @returns {Long} Value read\n */\n\n/**\n * Reads a zig-zag encoded varint as a signed 64 bit value.\n * @name Reader#sint64\n * @function\n * @returns {Long} Value read\n */\n\n/**\n * Reads a varint as a boolean.\n * @returns {boolean} Value read\n */\nReader.prototype.bool = function read_bool() {\n return this.uint32() !== 0;\n};\n\nfunction readFixed32_end(buf, end) { // note that this uses `end`, not `pos`\n return (buf[end - 4]\n | buf[end - 3] << 8\n | buf[end - 2] << 16\n | buf[end - 1] << 24) >>> 0;\n}\n\n/**\n * Reads fixed 32 bits as an unsigned 32 bit integer.\n * @returns {number} Value read\n */\nReader.prototype.fixed32 = function read_fixed32() {\n\n /* istanbul ignore if */\n if (this.pos + 4 > this.len)\n throw indexOutOfRange(this, 4);\n\n return readFixed32_end(this.buf, this.pos += 4);\n};\n\n/**\n * Reads fixed 32 bits as a signed 32 bit integer.\n * @returns {number} Value read\n */\nReader.prototype.sfixed32 = function read_sfixed32() {\n\n /* istanbul ignore if */\n if (this.pos + 4 > this.len)\n throw indexOutOfRange(this, 4);\n\n return readFixed32_end(this.buf, this.pos += 4) | 0;\n};\n\n/* eslint-disable no-invalid-this */\n\nfunction readFixed64(/* this: Reader */) {\n\n /* istanbul ignore if */\n if (this.pos + 8 > this.len)\n throw indexOutOfRange(this, 8);\n\n return new LongBits(readFixed32_end(this.buf, this.pos += 4), readFixed32_end(this.buf, this.pos += 4));\n}\n\n/* eslint-enable no-invalid-this */\n\n/**\n * Reads fixed 64 bits.\n * @name Reader#fixed64\n * @function\n * @returns {Long} Value read\n */\n\n/**\n * Reads zig-zag encoded fixed 64 bits.\n * @name Reader#sfixed64\n * @function\n * @returns {Long} Value read\n */\n\n/**\n * Reads a float (32 bit) as a number.\n * @function\n * @returns {number} Value read\n */\nReader.prototype.float = function read_float() {\n\n /* istanbul ignore if */\n if (this.pos + 4 > this.len)\n throw indexOutOfRange(this, 4);\n\n var value = util.float.readFloatLE(this.buf, this.pos);\n this.pos += 4;\n return value;\n};\n\n/**\n * Reads a double (64 bit float) as a number.\n * @function\n * @returns {number} Value read\n */\nReader.prototype.double = function read_double() {\n\n /* istanbul ignore if */\n if (this.pos + 8 > this.len)\n throw indexOutOfRange(this, 4);\n\n var value = util.float.readDoubleLE(this.buf, this.pos);\n this.pos += 8;\n return value;\n};\n\n/**\n * Reads a sequence of bytes preceeded by its length as a varint.\n * @returns {Uint8Array} Value read\n */\nReader.prototype.bytes = function read_bytes() {\n var length = this.uint32(),\n start = this.pos,\n end = this.pos + length;\n\n /* istanbul ignore if */\n if (end > this.len)\n throw indexOutOfRange(this, length);\n\n this.pos += length;\n if (Array.isArray(this.buf)) // plain array\n return this.buf.slice(start, end);\n\n if (start === end) { // fix for IE 10/Win8 and others' subarray returning array of size 1\n var nativeBuffer = util.Buffer;\n return nativeBuffer\n ? nativeBuffer.alloc(0)\n : new this.buf.constructor(0);\n }\n return this._slice.call(this.buf, start, end);\n};\n\n/**\n * Reads a string preceeded by its byte length as a varint.\n * @returns {string} Value read\n */\nReader.prototype.string = function read_string() {\n var bytes = this.bytes();\n return utf8.read(bytes, 0, bytes.length);\n};\n\n/**\n * Skips the specified number of bytes if specified, otherwise skips a varint.\n * @param {number} [length] Length if known, otherwise a varint is assumed\n * @returns {Reader} `this`\n */\nReader.prototype.skip = function skip(length) {\n if (typeof length === \"number\") {\n /* istanbul ignore if */\n if (this.pos + length > this.len)\n throw indexOutOfRange(this, length);\n this.pos += length;\n } else {\n do {\n /* istanbul ignore if */\n if (this.pos >= this.len)\n throw indexOutOfRange(this);\n } while (this.buf[this.pos++] & 128);\n }\n return this;\n};\n\n/**\n * Skips the next element of the specified wire type.\n * @param {number} wireType Wire type received\n * @returns {Reader} `this`\n */\nReader.prototype.skipType = function(wireType) {\n switch (wireType) {\n case 0:\n this.skip();\n break;\n case 1:\n this.skip(8);\n break;\n case 2:\n this.skip(this.uint32());\n break;\n case 3:\n while ((wireType = this.uint32() & 7) !== 4) {\n this.skipType(wireType);\n }\n break;\n case 5:\n this.skip(4);\n break;\n\n /* istanbul ignore next */\n default:\n throw Error(\"invalid wire type \" + wireType + \" at offset \" + this.pos);\n }\n return this;\n};\n\nReader._configure = function(BufferReader_) {\n BufferReader = BufferReader_;\n Reader.create = create();\n BufferReader._configure();\n\n var fn = util.Long ? \"toLong\" : /* istanbul ignore next */ \"toNumber\";\n util.merge(Reader.prototype, {\n\n int64: function read_int64() {\n return readLongVarint.call(this)[fn](false);\n },\n\n uint64: function read_uint64() {\n return readLongVarint.call(this)[fn](true);\n },\n\n sint64: function read_sint64() {\n return readLongVarint.call(this).zzDecode()[fn](false);\n },\n\n fixed64: function read_fixed64() {\n return readFixed64.call(this)[fn](true);\n },\n\n sfixed64: function read_sfixed64() {\n return readFixed64.call(this)[fn](false);\n }\n\n });\n};\n","\"use strict\";\nmodule.exports = BufferReader;\n\n// extends Reader\nvar Reader = require(\"./reader\");\n(BufferReader.prototype = Object.create(Reader.prototype)).constructor = BufferReader;\n\nvar util = require(\"./util/minimal\");\n\n/**\n * Constructs a new buffer reader instance.\n * @classdesc Wire format reader using node buffers.\n * @extends Reader\n * @constructor\n * @param {Buffer} buffer Buffer to read from\n */\nfunction BufferReader(buffer) {\n Reader.call(this, buffer);\n\n /**\n * Read buffer.\n * @name BufferReader#buf\n * @type {Buffer}\n */\n}\n\nBufferReader._configure = function () {\n /* istanbul ignore else */\n if (util.Buffer)\n BufferReader.prototype._slice = util.Buffer.prototype.slice;\n};\n\n\n/**\n * @override\n */\nBufferReader.prototype.string = function read_string_buffer() {\n var len = this.uint32(); // modifies pos\n return this.buf.utf8Slice\n ? this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + len, this.len))\n : this.buf.toString(\"utf-8\", this.pos, this.pos = Math.min(this.pos + len, this.len));\n};\n\n/**\n * Reads a sequence of bytes preceeded by its length as a varint.\n * @name BufferReader#bytes\n * @function\n * @returns {Buffer} Value read\n */\n\nBufferReader._configure();\n","\"use strict\";\nmodule.exports = {};\n\n/**\n * Named roots.\n * This is where pbjs stores generated structures (the option `-r, --root` specifies a name).\n * Can also be used manually to make roots available across modules.\n * @name roots\n * @type {Object.<string,Root>}\n * @example\n * // pbjs -r myroot -o compiled.js ...\n *\n * // in another module:\n * require(\"./compiled.js\");\n *\n * // in any subsequent module:\n * var root = protobuf.roots[\"myroot\"];\n */\n","\"use strict\";\n\n/**\n * Streaming RPC helpers.\n * @namespace\n */\nvar rpc = exports;\n\n/**\n * RPC implementation passed to {@link Service#create} performing a service request on network level, i.e. by utilizing http requests or websockets.\n * @typedef RPCImpl\n * @type {function}\n * @param {Method|rpc.ServiceMethod<Message<{}>,Message<{}>>} method Reflected or static method being called\n * @param {Uint8Array} requestData Request data\n * @param {RPCImplCallback} callback Callback function\n * @returns {undefined}\n * @example\n * function rpcImpl(method, requestData, callback) {\n * if (protobuf.util.lcFirst(method.name) !== \"myMethod\") // compatible with static code\n * throw Error(\"no such method\");\n * asynchronouslyObtainAResponse(requestData, function(err, responseData) {\n * callback(err, responseData);\n * });\n * }\n */\n\n/**\n * Node-style callback as used by {@link RPCImpl}.\n * @typedef RPCImplCallback\n * @type {function}\n * @param {Error|null} error Error, if any, otherwise `null`\n * @param {Uint8Array|null} [response] Response data or `null` to signal end of stream, if there hasn't been an error\n * @returns {undefined}\n */\n\nrpc.Service = require(\"./rpc/service\");\n","\"use strict\";\nmodule.exports = Service;\n\nvar util = require(\"../util/minimal\");\n\n// Extends EventEmitter\n(Service.prototype = Object.create(util.EventEmitter.prototype)).constructor = Service;\n\n/**\n * A service method callback as used by {@link rpc.ServiceMethod|ServiceMethod}.\n *\n * Differs from {@link RPCImplCallback} in that it is an actual callback of a service method which may not return `response = null`.\n * @typedef rpc.ServiceMethodCallback\n * @template TRes extends Message<TRes>\n * @type {function}\n * @param {Error|null} error Error, if any\n * @param {TRes} [response] Response message\n * @returns {undefined}\n */\n\n/**\n * A service method part of a {@link rpc.Service} as created by {@link Service.create}.\n * @typedef rpc.ServiceMethod\n * @template TReq extends Message<TReq>\n * @template TRes extends Message<TRes>\n * @type {function}\n * @param {TReq|Properties<TReq>} request Request message or plain object\n * @param {rpc.ServiceMethodCallback<TRes>} [callback] Node-style callback called with the error, if any, and the response message\n * @returns {Promise<Message<TRes>>} Promise if `callback` has been omitted, otherwise `undefined`\n */\n\n/**\n * Constructs a new RPC service instance.\n * @classdesc An RPC service as returned by {@link Service#create}.\n * @exports rpc.Service\n * @extends util.EventEmitter\n * @constructor\n * @param {RPCImpl} rpcImpl RPC implementation\n * @param {boolean} [requestDelimited=false] Whether requests are length-delimited\n * @param {boolean} [responseDelimited=false] Whether responses are length-delimited\n */\nfunction Service(rpcImpl, requestDelimited, responseDelimited) {\n\n if (typeof rpcImpl !== \"function\")\n throw TypeError(\"rpcImpl must be a function\");\n\n util.EventEmitter.call(this);\n\n /**\n * RPC implementation. Becomes `null` once the service is ended.\n * @type {RPCImpl|null}\n */\n this.rpcImpl = rpcImpl;\n\n /**\n * Whether requests are length-delimited.\n * @type {boolean}\n */\n this.requestDelimited = Boolean(requestDelimited);\n\n /**\n * Whether responses are length-delimited.\n * @type {boolean}\n */\n this.responseDelimited = Boolean(responseDelimited);\n}\n\n/**\n * Calls a service method through {@link rpc.Service#rpcImpl|rpcImpl}.\n * @param {Method|rpc.ServiceMethod<TReq,TRes>} method Reflected or static method\n * @param {Constructor<TReq>} requestCtor Request constructor\n * @param {Constructor<TRes>} responseCtor Response constructor\n * @param {TReq|Properties<TReq>} request Request message or plain object\n * @param {rpc.ServiceMethodCallback<TRes>} callback Service callback\n * @returns {undefined}\n * @template TReq extends Message<TReq>\n * @template TRes extends Message<TRes>\n */\nService.prototype.rpcCall = function rpcCall(method, requestCtor, responseCtor, request, callback) {\n\n if (!request)\n throw TypeError(\"request must be specified\");\n\n var self = this;\n if (!callback)\n return util.asPromise(rpcCall, self, method, requestCtor, responseCtor, request);\n\n if (!self.rpcImpl) {\n setTimeout(function() { callback(Error(\"already ended\")); }, 0);\n return undefined;\n }\n\n try {\n return self.rpcImpl(\n method,\n requestCtor[self.requestDelimited ? \"encodeDelimited\" : \"encode\"](request).finish(),\n function rpcCallback(err, response) {\n\n if (err) {\n self.emit(\"error\", err, method);\n return callback(err);\n }\n\n if (response === null) {\n self.end(/* endedByRPC */ true);\n return undefined;\n }\n\n if (!(response instanceof responseCtor)) {\n try {\n response = responseCtor[self.responseDelimited ? \"decodeDelimited\" : \"decode\"](response);\n } catch (err) {\n self.emit(\"error\", err, method);\n return callback(err);\n }\n }\n\n self.emit(\"data\", response, method);\n return callback(null, response);\n }\n );\n } catch (err) {\n self.emit(\"error\", err, method);\n setTimeout(function() { callback(err); }, 0);\n return undefined;\n }\n};\n\n/**\n * Ends this service and emits the `end` event.\n * @param {boolean} [endedByRPC=false] Whether the service has been ended by the RPC implementation.\n * @returns {rpc.Service} `this`\n */\nService.prototype.end = function end(endedByRPC) {\n if (this.rpcImpl) {\n if (!endedByRPC) // signal end to rpcImpl\n this.rpcImpl(null, null, null);\n this.rpcImpl = null;\n this.emit(\"end\").off();\n }\n return this;\n};\n","\"use strict\";\nmodule.exports = LongBits;\n\nvar util = require(\"../util/minimal\");\n\n/**\n * Constructs new long bits.\n * @classdesc Helper class for working with the low and high bits of a 64 bit value.\n * @memberof util\n * @constructor\n * @param {number} lo Low 32 bits, unsigned\n * @param {number} hi High 32 bits, unsigned\n */\nfunction LongBits(lo, hi) {\n\n // note that the casts below are theoretically unnecessary as of today, but older statically\n // generated converter code might still call the ctor with signed 32bits. kept for compat.\n\n /**\n * Low bits.\n * @type {number}\n */\n this.lo = lo >>> 0;\n\n /**\n * High bits.\n * @type {number}\n */\n this.hi = hi >>> 0;\n}\n\n/**\n * Zero bits.\n * @memberof util.LongBits\n * @type {util.LongBits}\n */\nvar zero = LongBits.zero = new LongBits(0, 0);\n\nzero.toNumber = function() { return 0; };\nzero.zzEncode = zero.zzDecode = function() { return this; };\nzero.length = function() { return 1; };\n\n/**\n * Zero hash.\n * @memberof util.LongBits\n * @type {string}\n */\nvar zeroHash = LongBits.zeroHash = \"\\0\\0\\0\\0\\0\\0\\0\\0\";\n\n/**\n * Constructs new long bits from the specified number.\n * @param {number} value Value\n * @returns {util.LongBits} Instance\n */\nLongBits.fromNumber = function fromNumber(value) {\n if (value === 0)\n return zero;\n var sign = value < 0;\n if (sign)\n value = -value;\n var lo = value >>> 0,\n hi = (value - lo) / 4294967296 >>> 0;\n if (sign) {\n hi = ~hi >>> 0;\n lo = ~lo >>> 0;\n if (++lo > 4294967295) {\n lo = 0;\n if (++hi > 4294967295)\n hi = 0;\n }\n }\n return new LongBits(lo, hi);\n};\n\n/**\n * Constructs new long bits from a number, long or string.\n * @param {Long|number|string} value Value\n * @returns {util.LongBits} Instance\n */\nLongBits.from = function from(value) {\n if (typeof value === \"number\")\n return LongBits.fromNumber(value);\n if (util.isString(value)) {\n /* istanbul ignore else */\n if (util.Long)\n value = util.Long.fromString(value);\n else\n return LongBits.fromNumber(parseInt(value, 10));\n }\n return value.low || value.high ? new LongBits(value.low >>> 0, value.high >>> 0) : zero;\n};\n\n/**\n * Converts this long bits to a possibly unsafe JavaScript number.\n * @param {boolean} [unsigned=false] Whether unsigned or not\n * @returns {number} Possibly unsafe number\n */\nLongBits.prototype.toNumber = function toNumber(unsigned) {\n if (!unsigned && this.hi >>> 31) {\n var lo = ~this.lo + 1 >>> 0,\n hi = ~this.hi >>> 0;\n if (!lo)\n hi = hi + 1 >>> 0;\n return -(lo + hi * 4294967296);\n }\n return this.lo + this.hi * 4294967296;\n};\n\n/**\n * Converts this long bits to a long.\n * @param {boolean} [unsigned=false] Whether unsigned or not\n * @returns {Long} Long\n */\nLongBits.prototype.toLong = function toLong(unsigned) {\n return util.Long\n ? new util.Long(this.lo | 0, this.hi | 0, Boolean(unsigned))\n /* istanbul ignore next */\n : { low: this.lo | 0, high: this.hi | 0, unsigned: Boolean(unsigned) };\n};\n\nvar charCodeAt = String.prototype.charCodeAt;\n\n/**\n * Constructs new long bits from the specified 8 characters long hash.\n * @param {string} hash Hash\n * @returns {util.LongBits} Bits\n */\nLongBits.fromHash = function fromHash(hash) {\n if (hash === zeroHash)\n return zero;\n return new LongBits(\n ( charCodeAt.call(hash, 0)\n | charCodeAt.call(hash, 1) << 8\n | charCodeAt.call(hash, 2) << 16\n | charCodeAt.call(hash, 3) << 24) >>> 0\n ,\n ( charCodeAt.call(hash, 4)\n | charCodeAt.call(hash, 5) << 8\n | charCodeAt.call(hash, 6) << 16\n | charCodeAt.call(hash, 7) << 24) >>> 0\n );\n};\n\n/**\n * Converts this long bits to a 8 characters long hash.\n * @returns {string} Hash\n */\nLongBits.prototype.toHash = function toHash() {\n return String.fromCharCode(\n this.lo & 255,\n this.lo >>> 8 & 255,\n this.lo >>> 16 & 255,\n this.lo >>> 24 ,\n this.hi & 255,\n this.hi >>> 8 & 255,\n this.hi >>> 16 & 255,\n this.hi >>> 24\n );\n};\n\n/**\n * Zig-zag encodes this long bits.\n * @returns {util.LongBits} `this`\n */\nLongBits.prototype.zzEncode = function zzEncode() {\n var mask = this.hi >> 31;\n this.hi = ((this.hi << 1 | this.lo >>> 31) ^ mask) >>> 0;\n this.lo = ( this.lo << 1 ^ mask) >>> 0;\n return this;\n};\n\n/**\n * Zig-zag decodes this long bits.\n * @returns {util.LongBits} `this`\n */\nLongBits.prototype.zzDecode = function zzDecode() {\n var mask = -(this.lo & 1);\n this.lo = ((this.lo >>> 1 | this.hi << 31) ^ mask) >>> 0;\n this.hi = ( this.hi >>> 1 ^ mask) >>> 0;\n return this;\n};\n\n/**\n * Calculates the length of this longbits when encoded as a varint.\n * @returns {number} Length\n */\nLongBits.prototype.length = function length() {\n var part0 = this.lo,\n part1 = (this.lo >>> 28 | this.hi << 4) >>> 0,\n part2 = this.hi >>> 24;\n return part2 === 0\n ? part1 === 0\n ? part0 < 16384\n ? part0 < 128 ? 1 : 2\n : part0 < 2097152 ? 3 : 4\n : part1 < 16384\n ? part1 < 128 ? 5 : 6\n : part1 < 2097152 ? 7 : 8\n : part2 < 128 ? 9 : 10;\n};\n","\"use strict\";\nvar util = exports;\n\n// used to return a Promise where callback is omitted\nutil.asPromise = require(\"@protobufjs/aspromise\");\n\n// converts to / from base64 encoded strings\nutil.base64 = require(\"@protobufjs/base64\");\n\n// base class of rpc.Service\nutil.EventEmitter = require(\"@protobufjs/eventemitter\");\n\n// float handling accross browsers\nutil.float = require(\"@protobufjs/float\");\n\n// requires modules optionally and hides the call from bundlers\nutil.inquire = require(\"@protobufjs/inquire\");\n\n// converts to / from utf8 encoded strings\nutil.utf8 = require(\"@protobufjs/utf8\");\n\n// provides a node-like buffer pool in the browser\nutil.pool = require(\"@protobufjs/pool\");\n\n// utility to work with the low and high bits of a 64 bit value\nutil.LongBits = require(\"./longbits\");\n\n/**\n * Whether running within node or not.\n * @memberof util\n * @type {boolean}\n */\nutil.isNode = Boolean(typeof global !== \"undefined\"\n && global\n && global.process\n && global.process.versions\n && global.process.versions.node);\n\n/**\n * Global object reference.\n * @memberof util\n * @type {Object}\n */\nutil.global = util.isNode && global\n || typeof window !== \"undefined\" && window\n || typeof self !== \"undefined\" && self\n || this; // eslint-disable-line no-invalid-this\n\n/**\n * An immuable empty array.\n * @memberof util\n * @type {Array.<*>}\n * @const\n */\nutil.emptyArray = Object.freeze ? Object.freeze([]) : /* istanbul ignore next */ []; // used on prototypes\n\n/**\n * An immutable empty object.\n * @type {Object}\n * @const\n */\nutil.emptyObject = Object.freeze ? Object.freeze({}) : /* istanbul ignore next */ {}; // used on prototypes\n\n/**\n * Tests if the specified value is an integer.\n * @function\n * @param {*} value Value to test\n * @returns {boolean} `true` if the value is an integer\n */\nutil.isInteger = Number.isInteger || /* istanbul ignore next */ function isInteger(value) {\n return typeof value === \"number\" && isFinite(value) && Math.floor(value) === value;\n};\n\n/**\n * Tests if the specified value is a string.\n * @param {*} value Value to test\n * @returns {boolean} `true` if the value is a string\n */\nutil.isString = function isString(value) {\n return typeof value === \"string\" || value instanceof String;\n};\n\n/**\n * Tests if the specified value is a non-null object.\n * @param {*} value Value to test\n * @returns {boolean} `true` if the value is a non-null object\n */\nutil.isObject = function isObject(value) {\n return value && typeof value === \"object\";\n};\n\n/**\n * Checks if a property on a message is considered to be present.\n * This is an alias of {@link util.isSet}.\n * @function\n * @param {Object} obj Plain object or message instance\n * @param {string} prop Property name\n * @returns {boolean} `true` if considered to be present, otherwise `false`\n */\nutil.isset =\n\n/**\n * Checks if a property on a message is considered to be present.\n * @param {Object} obj Plain object or message instance\n * @param {string} prop Property name\n * @returns {boolean} `true` if considered to be present, otherwise `false`\n */\nutil.isSet = function isSet(obj, prop) {\n var value = obj[prop];\n if (value != null && obj.hasOwnProperty(prop)) // eslint-disable-line eqeqeq, no-prototype-builtins\n return typeof value !== \"object\" || (Array.isArray(value) ? value.length : Object.keys(value).length) > 0;\n return false;\n};\n\n/**\n * Any compatible Buffer instance.\n * This is a minimal stand-alone definition of a Buffer instance. The actual type is that exported by node's typings.\n * @interface Buffer\n * @extends Uint8Array\n */\n\n/**\n * Node's Buffer class if available.\n * @type {Constructor<Buffer>}\n */\nutil.Buffer = (function() {\n try {\n var Buffer = util.inquire(\"buffer\").Buffer;\n // refuse to use non-node buffers if not explicitly assigned (perf reasons):\n return Buffer.prototype.utf8Write ? Buffer : /* istanbul ignore next */ null;\n } catch (e) {\n /* istanbul ignore next */\n return null;\n }\n})();\n\n// Internal alias of or polyfull for Buffer.from.\nutil._Buffer_from = null;\n\n// Internal alias of or polyfill for Buffer.allocUnsafe.\nutil._Buffer_allocUnsafe = null;\n\n/**\n * Creates a new buffer of whatever type supported by the environment.\n * @param {number|number[]} [sizeOrArray=0] Buffer size or number array\n * @returns {Uint8Array|Buffer} Buffer\n */\nutil.newBuffer = function newBuffer(sizeOrArray) {\n /* istanbul ignore next */\n return typeof sizeOrArray === \"number\"\n ? util.Buffer\n ? util._Buffer_allocUnsafe(sizeOrArray)\n : new util.Array(sizeOrArray)\n : util.Buffer\n ? util._Buffer_from(sizeOrArray)\n : typeof Uint8Array === \"undefined\"\n ? sizeOrArray\n : new Uint8Array(sizeOrArray);\n};\n\n/**\n * Array implementation used in the browser. `Uint8Array` if supported, otherwise `Array`.\n * @type {Constructor<Uint8Array>}\n */\nutil.Array = typeof Uint8Array !== \"undefined\" ? Uint8Array /* istanbul ignore next */ : Array;\n\n/**\n * Any compatible Long instance.\n * This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js.\n * @interface Long\n * @property {number} low Low bits\n * @property {number} high High bits\n * @property {boolean} unsigned Whether unsigned or not\n */\n\n/**\n * Long.js's Long class if available.\n * @type {Constructor<Long>}\n */\nutil.Long = /* istanbul ignore next */ util.global.dcodeIO && /* istanbul ignore next */ util.global.dcodeIO.Long\n || /* istanbul ignore next */ util.global.Long\n || util.inquire(\"long\");\n\n/**\n * Regular expression used to verify 2 bit (`bool`) map keys.\n * @type {RegExp}\n * @const\n */\nutil.key2Re = /^true|false|0|1$/;\n\n/**\n * Regular expression used to verify 32 bit (`int32` etc.) map keys.\n * @type {RegExp}\n * @const\n */\nutil.key32Re = /^-?(?:0|[1-9][0-9]*)$/;\n\n/**\n * Regular expression used to verify 64 bit (`int64` etc.) map keys.\n * @type {RegExp}\n * @const\n */\nutil.key64Re = /^(?:[\\\\x00-\\\\xff]{8}|-?(?:0|[1-9][0-9]*))$/;\n\n/**\n * Converts a number or long to an 8 characters long hash string.\n * @param {Long|number} value Value to convert\n * @returns {string} Hash\n */\nutil.longToHash = function longToHash(value) {\n return value\n ? util.LongBits.from(value).toHash()\n : util.LongBits.zeroHash;\n};\n\n/**\n * Converts an 8 characters long hash string to a long or number.\n * @param {string} hash Hash\n * @param {boolean} [unsigned=false] Whether unsigned or not\n * @returns {Long|number} Original value\n */\nutil.longFromHash = function longFromHash(hash, unsigned) {\n var bits = util.LongBits.fromHash(hash);\n if (util.Long)\n return util.Long.fromBits(bits.lo, bits.hi, unsigned);\n return bits.toNumber(Boolean(unsigned));\n};\n\n/**\n * Merges the properties of the source object into the destination object.\n * @memberof util\n * @param {Object.<string,*>} dst Destination object\n * @param {Object.<string,*>} src Source object\n * @param {boolean} [ifNotSet=false] Merges only if the key is not already set\n * @returns {Object.<string,*>} Destination object\n */\nfunction merge(dst, src, ifNotSet) { // used by converters\n for (var keys = Object.keys(src), i = 0; i < keys.length; ++i)\n if (dst[keys[i]] === undefined || !ifNotSet)\n dst[keys[i]] = src[keys[i]];\n return dst;\n}\n\nutil.merge = merge;\n\n/**\n * Converts the first character of a string to lower case.\n * @param {string} str String to convert\n * @returns {string} Converted string\n */\nutil.lcFirst = function lcFirst(str) {\n return str.charAt(0).toLowerCase() + str.substring(1);\n};\n\n/**\n * Creates a custom error constructor.\n * @memberof util\n * @param {string} name Error name\n * @returns {Constructor<Error>} Custom error constructor\n */\nfunction newError(name) {\n\n function CustomError(message, properties) {\n\n if (!(this instanceof CustomError))\n return new CustomError(message, properties);\n\n // Error.call(this, message);\n // ^ just returns a new error instance because the ctor can be called as a function\n\n Object.defineProperty(this, \"message\", { get: function() { return message; } });\n\n /* istanbul ignore next */\n if (Error.captureStackTrace) // node\n Error.captureStackTrace(this, CustomError);\n else\n Object.defineProperty(this, \"stack\", { value: new Error().stack || \"\" });\n\n if (properties)\n merge(this, properties);\n }\n\n CustomError.prototype = Object.create(Error.prototype, {\n constructor: {\n value: CustomError,\n writable: true,\n enumerable: false,\n configurable: true,\n },\n name: {\n get: function get() { return name; },\n set: undefined,\n enumerable: false,\n // configurable: false would accurately preserve the behavior of\n // the original, but I'm guessing that was not intentional.\n // For an actual error subclass, this property would\n // be configurable.\n configurable: true,\n },\n toString: {\n value: function value() { return this.name + \": \" + this.message; },\n writable: true,\n enumerable: false,\n configurable: true,\n },\n });\n\n return CustomError;\n}\n\nutil.newError = newError;\n\n/**\n * Constructs a new protocol error.\n * @classdesc Error subclass indicating a protocol specifc error.\n * @memberof util\n * @extends Error\n * @template T extends Message<T>\n * @constructor\n * @param {string} message Error message\n * @param {Object.<string,*>} [properties] Additional properties\n * @example\n * try {\n * MyMessage.decode(someBuffer); // throws if required fields are missing\n * } catch (e) {\n * if (e instanceof ProtocolError && e.instance)\n * console.log(\"decoded so far: \" + JSON.stringify(e.instance));\n * }\n */\nutil.ProtocolError = newError(\"ProtocolError\");\n\n/**\n * So far decoded message instance.\n * @name util.ProtocolError#instance\n * @type {Message<T>}\n */\n\n/**\n * A OneOf getter as returned by {@link util.oneOfGetter}.\n * @typedef OneOfGetter\n * @type {function}\n * @returns {string|undefined} Set field name, if any\n */\n\n/**\n * Builds a getter for a oneof's present field name.\n * @param {string[]} fieldNames Field names\n * @returns {OneOfGetter} Unbound getter\n */\nutil.oneOfGetter = function getOneOf(fieldNames) {\n var fieldMap = {};\n for (var i = 0; i < fieldNames.length; ++i)\n fieldMap[fieldNames[i]] = 1;\n\n /**\n * @returns {string|undefined} Set field name, if any\n * @this Object\n * @ignore\n */\n return function() { // eslint-disable-line consistent-return\n for (var keys = Object.keys(this), i = keys.length - 1; i > -1; --i)\n if (fieldMap[keys[i]] === 1 && this[keys[i]] !== undefined && this[keys[i]] !== null)\n return keys[i];\n };\n};\n\n/**\n * A OneOf setter as returned by {@link util.oneOfSetter}.\n * @typedef OneOfSetter\n * @type {function}\n * @param {string|undefined} value Field name\n * @returns {undefined}\n */\n\n/**\n * Builds a setter for a oneof's present field name.\n * @param {string[]} fieldNames Field names\n * @returns {OneOfSetter} Unbound setter\n */\nutil.oneOfSetter = function setOneOf(fieldNames) {\n\n /**\n * @param {string} name Field name\n * @returns {undefined}\n * @this Object\n * @ignore\n */\n return function(name) {\n for (var i = 0; i < fieldNames.length; ++i)\n if (fieldNames[i] !== name)\n delete this[fieldNames[i]];\n };\n};\n\n/**\n * Default conversion options used for {@link Message#toJSON} implementations.\n *\n * These options are close to proto3's JSON mapping with the exception that internal types like Any are handled just like messages. More precisely:\n *\n * - Longs become strings\n * - Enums become string keys\n * - Bytes become base64 encoded strings\n * - (Sub-)Messages become plain objects\n * - Maps become plain objects with all string keys\n * - Repeated fields become arrays\n * - NaN and Infinity for float and double fields become strings\n *\n * @type {IConversionOptions}\n * @see https://developers.google.com/protocol-buffers/docs/proto3?hl=en#json\n */\nutil.toJSONOptions = {\n longs: String,\n enums: String,\n bytes: String,\n json: true\n};\n\n// Sets up buffer utility according to the environment (called in index-minimal)\nutil._configure = function() {\n var Buffer = util.Buffer;\n /* istanbul ignore if */\n if (!Buffer) {\n util._Buffer_from = util._Buffer_allocUnsafe = null;\n return;\n }\n // because node 4.x buffers are incompatible & immutable\n // see: https://github.com/dcodeIO/protobuf.js/pull/665\n util._Buffer_from = Buffer.from !== Uint8Array.from && Buffer.from ||\n /* istanbul ignore next */\n function Buffer_from(value, encoding) {\n return new Buffer(value, encoding);\n };\n util._Buffer_allocUnsafe = Buffer.allocUnsafe ||\n /* istanbul ignore next */\n function Buffer_allocUnsafe(size) {\n return new Buffer(size);\n };\n};\n","\"use strict\";\nmodule.exports = Writer;\n\nvar util = require(\"./util/minimal\");\n\nvar BufferWriter; // cyclic\n\nvar LongBits = util.LongBits,\n base64 = util.base64,\n utf8 = util.utf8;\n\n/**\n * Constructs a new writer operation instance.\n * @classdesc Scheduled writer operation.\n * @constructor\n * @param {function(*, Uint8Array, number)} fn Function to call\n * @param {number} len Value byte length\n * @param {*} val Value to write\n * @ignore\n */\nfunction Op(fn, len, val) {\n\n /**\n * Function to call.\n * @type {function(Uint8Array, number, *)}\n */\n this.fn = fn;\n\n /**\n * Value byte length.\n * @type {number}\n */\n this.len = len;\n\n /**\n * Next operation.\n * @type {Writer.Op|undefined}\n */\n this.next = undefined;\n\n /**\n * Value to write.\n * @type {*}\n */\n this.val = val; // type varies\n}\n\n/* istanbul ignore next */\nfunction noop() {} // eslint-disable-line no-empty-function\n\n/**\n * Constructs a new writer state instance.\n * @classdesc Copied writer state.\n * @memberof Writer\n * @constructor\n * @param {Writer} writer Writer to copy state from\n * @ignore\n */\nfunction State(writer) {\n\n /**\n * Current head.\n * @type {Writer.Op}\n */\n this.head = writer.head;\n\n /**\n * Current tail.\n * @type {Writer.Op}\n */\n this.tail = writer.tail;\n\n /**\n * Current buffer length.\n * @type {number}\n */\n this.len = writer.len;\n\n /**\n * Next state.\n * @type {State|null}\n */\n this.next = writer.states;\n}\n\n/**\n * Constructs a new writer instance.\n * @classdesc Wire format writer using `Uint8Array` if available, otherwise `Array`.\n * @constructor\n */\nfunction Writer() {\n\n /**\n * Current length.\n * @type {number}\n */\n this.len = 0;\n\n /**\n * Operations head.\n * @type {Object}\n */\n this.head = new Op(noop, 0, 0);\n\n /**\n * Operations tail\n * @type {Object}\n */\n this.tail = this.head;\n\n /**\n * Linked forked states.\n * @type {Object|null}\n */\n this.states = null;\n\n // When a value is written, the writer calculates its byte length and puts it into a linked\n // list of operations to perform when finish() is called. This both allows us to allocate\n // buffers of the exact required size and reduces the amount of work we have to do compared\n // to first calculating over objects and then encoding over objects. In our case, the encoding\n // part is just a linked list walk calling operations with already prepared values.\n}\n\nvar create = function create() {\n return util.Buffer\n ? function create_buffer_setup() {\n return (Writer.create = function create_buffer() {\n return new BufferWriter();\n })();\n }\n /* istanbul ignore next */\n : function create_array() {\n return new Writer();\n };\n};\n\n/**\n * Creates a new writer.\n * @function\n * @returns {BufferWriter|Writer} A {@link BufferWriter} when Buffers are supported, otherwise a {@link Writer}\n */\nWriter.create = create();\n\n/**\n * Allocates a buffer of the specified size.\n * @param {number} size Buffer size\n * @returns {Uint8Array} Buffer\n */\nWriter.alloc = function alloc(size) {\n return new util.Array(size);\n};\n\n// Use Uint8Array buffer pool in the browser, just like node does with buffers\n/* istanbul ignore else */\nif (util.Array !== Array)\n Writer.alloc = util.pool(Writer.alloc, util.Array.prototype.subarray);\n\n/**\n * Pushes a new operation to the queue.\n * @param {function(Uint8Array, number, *)} fn Function to call\n * @param {number} len Value byte length\n * @param {number} val Value to write\n * @returns {Writer} `this`\n * @private\n */\nWriter.prototype._push = function push(fn, len, val) {\n this.tail = this.tail.next = new Op(fn, len, val);\n this.len += len;\n return this;\n};\n\nfunction writeByte(val, buf, pos) {\n buf[pos] = val & 255;\n}\n\nfunction writeVarint32(val, buf, pos) {\n while (val > 127) {\n buf[pos++] = val & 127 | 128;\n val >>>= 7;\n }\n buf[pos] = val;\n}\n\n/**\n * Constructs a new varint writer operation instance.\n * @classdesc Scheduled varint writer operation.\n * @extends Op\n * @constructor\n * @param {number} len Value byte length\n * @param {number} val Value to write\n * @ignore\n */\nfunction VarintOp(len, val) {\n this.len = len;\n this.next = undefined;\n this.val = val;\n}\n\nVarintOp.prototype = Object.create(Op.prototype);\nVarintOp.prototype.fn = writeVarint32;\n\n/**\n * Writes an unsigned 32 bit value as a varint.\n * @param {number} value Value to write\n * @returns {Writer} `this`\n */\nWriter.prototype.uint32 = function write_uint32(value) {\n // here, the call to this.push has been inlined and a varint specific Op subclass is used.\n // uint32 is by far the most frequently used operation and benefits significantly from this.\n this.len += (this.tail = this.tail.next = new VarintOp(\n (value = value >>> 0)\n < 128 ? 1\n : value < 16384 ? 2\n : value < 2097152 ? 3\n : value < 268435456 ? 4\n : 5,\n value)).len;\n return this;\n};\n\n/**\n * Writes a signed 32 bit value as a varint.\n * @function\n * @param {number} value Value to write\n * @returns {Writer} `this`\n */\nWriter.prototype.int32 = function write_int32(value) {\n return value < 0\n ? this._push(writeVarint64, 10, LongBits.fromNumber(value)) // 10 bytes per spec\n : this.uint32(value);\n};\n\n/**\n * Writes a 32 bit value as a varint, zig-zag encoded.\n * @param {number} value Value to write\n * @returns {Writer} `this`\n */\nWriter.prototype.sint32 = function write_sint32(value) {\n return this.uint32((value << 1 ^ value >> 31) >>> 0);\n};\n\nfunction writeVarint64(val, buf, pos) {\n while (val.hi) {\n buf[pos++] = val.lo & 127 | 128;\n val.lo = (val.lo >>> 7 | val.hi << 25) >>> 0;\n val.hi >>>= 7;\n }\n while (val.lo > 127) {\n buf[pos++] = val.lo & 127 | 128;\n val.lo = val.lo >>> 7;\n }\n buf[pos++] = val.lo;\n}\n\n/**\n * Writes an unsigned 64 bit value as a varint.\n * @param {Long|number|string} value Value to write\n * @returns {Writer} `this`\n * @throws {TypeError} If `value` is a string and no long library is present.\n */\nWriter.prototype.uint64 = function write_uint64(value) {\n var bits = LongBits.from(value);\n return this._push(writeVarint64, bits.length(), bits);\n};\n\n/**\n * Writes a signed 64 bit value as a varint.\n * @function\n * @param {Long|number|string} value Value to write\n * @returns {Writer} `this`\n * @throws {TypeError} If `value` is a string and no long library is present.\n */\nWriter.prototype.int64 = Writer.prototype.uint64;\n\n/**\n * Writes a signed 64 bit value as a varint, zig-zag encoded.\n * @param {Long|number|string} value Value to write\n * @returns {Writer} `this`\n * @throws {TypeError} If `value` is a string and no long library is present.\n */\nWriter.prototype.sint64 = function write_sint64(value) {\n var bits = LongBits.from(value).zzEncode();\n return this._push(writeVarint64, bits.length(), bits);\n};\n\n/**\n * Writes a boolish value as a varint.\n * @param {boolean} value Value to write\n * @returns {Writer} `this`\n */\nWriter.prototype.bool = function write_bool(value) {\n return this._push(writeByte, 1, value ? 1 : 0);\n};\n\nfunction writeFixed32(val, buf, pos) {\n buf[pos ] = val & 255;\n buf[pos + 1] = val >>> 8 & 255;\n buf[pos + 2] = val >>> 16 & 255;\n buf[pos + 3] = val >>> 24;\n}\n\n/**\n * Writes an unsigned 32 bit value as fixed 32 bits.\n * @param {number} value Value to write\n * @returns {Writer} `this`\n */\nWriter.prototype.fixed32 = function write_fixed32(value) {\n return this._push(writeFixed32, 4, value >>> 0);\n};\n\n/**\n * Writes a signed 32 bit value as fixed 32 bits.\n * @function\n * @param {number} value Value to write\n * @returns {Writer} `this`\n */\nWriter.prototype.sfixed32 = Writer.prototype.fixed32;\n\n/**\n * Writes an unsigned 64 bit value as fixed 64 bits.\n * @param {Long|number|string} value Value to write\n * @returns {Writer} `this`\n * @throws {TypeError} If `value` is a string and no long library is present.\n */\nWriter.prototype.fixed64 = function write_fixed64(value) {\n var bits = LongBits.from(value);\n return this._push(writeFixed32, 4, bits.lo)._push(writeFixed32, 4, bits.hi);\n};\n\n/**\n * Writes a signed 64 bit value as fixed 64 bits.\n * @function\n * @param {Long|number|string} value Value to write\n * @returns {Writer} `this`\n * @throws {TypeError} If `value` is a string and no long library is present.\n */\nWriter.prototype.sfixed64 = Writer.prototype.fixed64;\n\n/**\n * Writes a float (32 bit).\n * @function\n * @param {number} value Value to write\n * @returns {Writer} `this`\n */\nWriter.prototype.float = function write_float(value) {\n return this._push(util.float.writeFloatLE, 4, value);\n};\n\n/**\n * Writes a double (64 bit float).\n * @function\n * @param {number} value Value to write\n * @returns {Writer} `this`\n */\nWriter.prototype.double = function write_double(value) {\n return this._push(util.float.writeDoubleLE, 8, value);\n};\n\nvar writeBytes = util.Array.prototype.set\n ? function writeBytes_set(val, buf, pos) {\n buf.set(val, pos); // also works for plain array values\n }\n /* istanbul ignore next */\n : function writeBytes_for(val, buf, pos) {\n for (var i = 0; i < val.length; ++i)\n buf[pos + i] = val[i];\n };\n\n/**\n * Writes a sequence of bytes.\n * @param {Uint8Array|string} value Buffer or base64 encoded string to write\n * @returns {Writer} `this`\n */\nWriter.prototype.bytes = function write_bytes(value) {\n var len = value.length >>> 0;\n if (!len)\n return this._push(writeByte, 1, 0);\n if (util.isString(value)) {\n var buf = Writer.alloc(len = base64.length(value));\n base64.decode(value, buf, 0);\n value = buf;\n }\n return this.uint32(len)._push(writeBytes, len, value);\n};\n\n/**\n * Writes a string.\n * @param {string} value Value to write\n * @returns {Writer} `this`\n */\nWriter.prototype.string = function write_string(value) {\n var len = utf8.length(value);\n return len\n ? this.uint32(len)._push(utf8.write, len, value)\n : this._push(writeByte, 1, 0);\n};\n\n/**\n * Forks this writer's state by pushing it to a stack.\n * Calling {@link Writer#reset|reset} or {@link Writer#ldelim|ldelim} resets the writer to the previous state.\n * @returns {Writer} `this`\n */\nWriter.prototype.fork = function fork() {\n this.states = new State(this);\n this.head = this.tail = new Op(noop, 0, 0);\n this.len = 0;\n return this;\n};\n\n/**\n * Resets this instance to the last state.\n * @returns {Writer} `this`\n */\nWriter.prototype.reset = function reset() {\n if (this.states) {\n this.head = this.states.head;\n this.tail = this.states.tail;\n this.len = this.states.len;\n this.states = this.states.next;\n } else {\n this.head = this.tail = new Op(noop, 0, 0);\n this.len = 0;\n }\n return this;\n};\n\n/**\n * Resets to the last state and appends the fork state's current write length as a varint followed by its operations.\n * @returns {Writer} `this`\n */\nWriter.prototype.ldelim = function ldelim() {\n var head = this.head,\n tail = this.tail,\n len = this.len;\n this.reset().uint32(len);\n if (len) {\n this.tail.next = head.next; // skip noop\n this.tail = tail;\n this.len += len;\n }\n return this;\n};\n\n/**\n * Finishes the write operation.\n * @returns {Uint8Array} Finished buffer\n */\nWriter.prototype.finish = function finish() {\n var head = this.head.next, // skip noop\n buf = this.constructor.alloc(this.len),\n pos = 0;\n while (head) {\n head.fn(head.val, buf, pos);\n pos += head.len;\n head = head.next;\n }\n // this.head = this.tail = null;\n return buf;\n};\n\nWriter._configure = function(BufferWriter_) {\n BufferWriter = BufferWriter_;\n Writer.create = create();\n BufferWriter._configure();\n};\n","\"use strict\";\nmodule.exports = BufferWriter;\n\n// extends Writer\nvar Writer = require(\"./writer\");\n(BufferWriter.prototype = Object.create(Writer.prototype)).constructor = BufferWriter;\n\nvar util = require(\"./util/minimal\");\n\n/**\n * Constructs a new buffer writer instance.\n * @classdesc Wire format writer using node buffers.\n * @extends Writer\n * @constructor\n */\nfunction BufferWriter() {\n Writer.call(this);\n}\n\nBufferWriter._configure = function () {\n /**\n * Allocates a buffer of the specified size.\n * @function\n * @param {number} size Buffer size\n * @returns {Buffer} Buffer\n */\n BufferWriter.alloc = util._Buffer_allocUnsafe;\n\n BufferWriter.writeBytesBuffer = util.Buffer && util.Buffer.prototype instanceof Uint8Array && util.Buffer.prototype.set.name === \"set\"\n ? function writeBytesBuffer_set(val, buf, pos) {\n buf.set(val, pos); // faster than copy (requires node >= 4 where Buffers extend Uint8Array and set is properly inherited)\n // also works for plain array values\n }\n /* istanbul ignore next */\n : function writeBytesBuffer_copy(val, buf, pos) {\n if (val.copy) // Buffer values\n val.copy(buf, pos, 0, val.length);\n else for (var i = 0; i < val.length;) // plain array values\n buf[pos++] = val[i++];\n };\n};\n\n\n/**\n * @override\n */\nBufferWriter.prototype.bytes = function write_bytes_buffer(value) {\n if (util.isString(value))\n value = util._Buffer_from(value, \"base64\");\n var len = value.length >>> 0;\n this.uint32(len);\n if (len)\n this._push(BufferWriter.writeBytesBuffer, len, value);\n return this;\n};\n\nfunction writeStringBuffer(val, buf, pos) {\n if (val.length < 40) // plain js is faster for short strings (probably due to redundant assertions)\n util.utf8.write(val, buf, pos);\n else if (buf.utf8Write)\n buf.utf8Write(val, pos);\n else\n buf.write(val, pos);\n}\n\n/**\n * @override\n */\nBufferWriter.prototype.string = function write_string_buffer(value) {\n var len = util.Buffer.byteLength(value);\n this.uint32(len);\n if (len)\n this._push(writeStringBuffer, len, value);\n return this;\n};\n\n\n/**\n * Finishes the write operation.\n * @name BufferWriter#finish\n * @function\n * @returns {Buffer} Finished buffer\n */\n\nBufferWriter._configure();\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","/**\n * DNT (Do Not Translate) preferences storage adapter\n * \n * Now uses document-type-based storage in the unified configuration.\n * When you mark a field as DNT for any document of a type (e.g., 'product'),\n * it applies to ALL documents of that type.\n * \n * This replaces the old per-document localStorage approach with centralized\n * configuration stored in Sanity.\n */\n\nimport { DNTPreferences, DNTStorage } from '../types/dnt';\nimport { UnifiedConfigStorage } from './unifiedConfigStorage';\n\n/**\n * DNT Storage Adapter using unified configuration\n */\nexport class DNTStorageAdapter implements DNTStorage {\n private configStorage: UnifiedConfigStorage;\n\n constructor(configStorage: UnifiedConfigStorage) {\n this.configStorage = configStorage;\n }\n\n /**\n * Get DNT field configuration for a document type\n */\n async getFieldsForType(documentType: string): Promise<Record<string, boolean>> {\n try {\n return await this.configStorage.getDNTFieldsForType(documentType);\n } catch (error) {\n console.error(`Failed to get DNT fields for type ${documentType}:`, error);\n return {};\n }\n }\n\n /**\n * Set DNT status for a specific field in a document type\n */\n async setFieldDNT(documentType: string, fieldPath: string, dnt: boolean): Promise<void> {\n try {\n await this.configStorage.setDNTField(documentType, fieldPath, dnt);\n console.log(`Set DNT=${dnt} for ${documentType}.${fieldPath} (applies to all ${documentType} documents)`);\n } catch (error) {\n console.error(`Failed to set DNT for ${documentType}.${fieldPath}:`, error);\n throw error;\n }\n }\n\n /**\n * Toggle DNT status for a field in a document type\n */\n async toggleFieldDNT(documentType: string, fieldPath: string): Promise<boolean> {\n try {\n const newStatus = await this.configStorage.toggleDNTField(documentType, fieldPath);\n console.log(`Toggled DNT to ${newStatus} for ${documentType}.${fieldPath} (applies to all ${documentType} documents)`);\n return newStatus;\n } catch (error) {\n console.error(`Failed to toggle DNT for ${documentType}.${fieldPath}:`, error);\n throw error;\n }\n }\n\n /**\n * Get DNT status for a specific field in a document type\n */\n async getFieldDNT(documentType: string, fieldPath: string): Promise<boolean> {\n try {\n return await this.configStorage.getDNTFieldStatus(documentType, fieldPath);\n } catch (error) {\n console.error(`Failed to get DNT status for ${documentType}.${fieldPath}:`, error);\n return false;\n }\n }\n\n /**\n * Clear all DNT fields for a document type\n */\n async clearFieldsForType(documentType: string): Promise<void> {\n try {\n await this.configStorage.clearDNTFieldsForType(documentType);\n console.log(`Cleared all DNT fields for type ${documentType}`);\n } catch (error) {\n console.error(`Failed to clear DNT fields for type ${documentType}:`, error);\n throw error;\n }\n }\n\n /**\n * Get all DNT configurations (all document types)\n */\n async getAllDNTFields(): Promise<Record<string, Record<string, boolean>>> {\n try {\n return await this.configStorage.getAllDNTFields();\n } catch (error) {\n console.error('Failed to get all DNT fields:', error);\n return {};\n }\n }\n\n // Legacy methods for backward compatibility with existing code\n \n /**\n * @deprecated Use getFieldsForType instead. This method now uses document type, not document ID.\n * Get DNT preferences - now based on document type, not individual document ID\n */\n async getPreferences(_documentId: string): Promise<DNTPreferences | null> {\n // For backward compatibility, we need to extract the document type from somewhere\n // This is a transitional method and should be updated in calling code\n console.warn('getPreferences(documentId) is deprecated. Use getFieldsForType(documentType) instead.');\n \n // Since we don't have the document type here, we can't provide accurate data\n // Calling code should be updated to use the new methods\n return null;\n }\n\n /**\n * @deprecated Use setFieldDNT instead\n */\n async savePreferences(preferences: DNTPreferences): Promise<void> {\n console.warn('savePreferences is deprecated. Use setFieldDNT instead.');\n \n // Migrate to new format: set each field for the document type\n for (const [fieldPath, dnt] of Object.entries(preferences.fields)) {\n await this.setFieldDNT(preferences.documentType, fieldPath, dnt);\n }\n }\n\n /**\n * @deprecated Use clearFieldsForType instead\n */\n async clearPreferences(_documentId: string): Promise<void> {\n console.warn('clearPreferences(documentId) is deprecated. Use clearFieldsForType(documentType) instead.');\n // Cannot clear without knowing document type\n // Calling code should be updated\n }\n}\n\n/**\n * Legacy DNT Storage Adapter using localStorage (deprecated)\n * Kept for migration purposes only\n * @deprecated Use DNTStorageAdapter with UnifiedConfigStorage instead\n */\nexport class LegacyDNTStorageAdapter {\n private static readonly STORAGE_KEY_PREFIX = 'sanity-translation-dnt-';\n\n private getStorageKey(documentId: string): string {\n return `${LegacyDNTStorageAdapter.STORAGE_KEY_PREFIX}${documentId}`;\n }\n\n async getPreferences(documentId: string): Promise<DNTPreferences | null> {\n try {\n const key = this.getStorageKey(documentId);\n const stored = localStorage.getItem(key);\n \n if (!stored) {\n return null;\n }\n\n return JSON.parse(stored) as DNTPreferences;\n } catch (error) {\n console.error(`Failed to get legacy DNT preferences for ${documentId}:`, error);\n return null;\n }\n }\n\n async savePreferences(preferences: DNTPreferences): Promise<void> {\n try {\n const key = this.getStorageKey(preferences.documentId);\n const toStore = {\n ...preferences,\n updatedAt: new Date().toISOString()\n };\n \n localStorage.setItem(key, JSON.stringify(toStore));\n } catch (error) {\n console.error(`Failed to save legacy DNT preferences:`, error);\n throw error;\n }\n }\n\n async clearPreferences(documentId: string): Promise<void> {\n try {\n const key = this.getStorageKey(documentId);\n localStorage.removeItem(key);\n } catch (error) {\n console.error(`Failed to clear legacy DNT preferences:`, error);\n throw error;\n }\n }\n\n /**\n * Migrate legacy localStorage preferences to unified configuration\n */\n async migrateToUnified(\n configStorage: UnifiedConfigStorage,\n documentId: string,\n documentType: string\n ): Promise<void> {\n const preferences = await this.getPreferences(documentId);\n if (!preferences) {\n return;\n }\n\n console.log(`Migrating DNT preferences for ${documentId} (${documentType}) to unified config...`);\n \n // Migrate each field to the document-type-based storage\n for (const [fieldPath, dnt] of Object.entries(preferences.fields)) {\n await configStorage.setDNTField(documentType, fieldPath, dnt);\n }\n\n // Clear the legacy localStorage entry\n await this.clearPreferences(documentId);\n \n console.log(`Migration complete for ${documentId}`);\n }\n}\n\n","/**\n * Unified Configuration Storage Adapter\n * \n * Provides centralized persistence for all plugin configuration using Sanity's document storage.\n * This replaces separate OAuth and Locale storage adapters with a single unified configuration.\n * \n * Stores in a single EL_PluginConfiguration document:\n * - OAuth configuration (projectId, accessToken)\n * - Locale definitions and settings\n * - DNT field mappings by document type\n */\n\nimport { SanityClient } from 'sanity';\nimport { OAuthConfig } from '../types/oauth';\nimport { LocaleConfig } from '../types/locale';\nimport { CollisionResolutionMode, ExistingDocumentHandling } from '../types/pluginConfig';\n\n/**\n * Configuration document ID for unified plugin settings\n * Internal type prefixed with EL_ to separate from customer document types\n */\nconst UNIFIED_CONFIG_DOC_ID = 'sanity-translation-plugin.config';\nconst UNIFIED_CONFIG_DOC_TYPE = 'EL_PluginConfiguration';\n\n/**\n * DNT field configuration in schema format (array)\n */\ninterface DNTFieldConfigurationSchema {\n documentType: string;\n fields: Array<{\n _key?: string;\n fieldPath: string;\n dnt: boolean;\n }>;\n}\n\n/**\n * Unified plugin configuration structure\n */\nexport interface UnifiedPluginConfig {\n /** OAuth/authentication settings */\n projectId?: string;\n accessToken?: string;\n \n /** Translation settings */\n translationApiEndpoint?: string;\n requestContentType?: 'application/json' | 'application/x-protobuf';\n responseAcceptHeader?: 'application/json' | 'application/x-protobuf';\n defaultDocumentCreationMode?: 'draft' | 'published';\n \n /** Collision resolution settings */\n collisionResolutionMode?: CollisionResolutionMode;\n existingDocumentHandling?: ExistingDocumentHandling;\n \n /** Locale configuration */\n locales?: LocaleConfig['locales'];\n defaultLocale?: string;\n \n /** DNT field map: { [documentType]: { [fieldPath]: boolean } } */\n dntFieldMap?: Record<string, Record<string, boolean>>;\n \n /** Debug mode - when enabled, shows additional DNT badges on all fields */\n debugMode?: boolean;\n \n /** Configuration version for migrations */\n version?: string;\n \n /** Last updated timestamp */\n lastUpdated?: string;\n}\n\n/**\n * Unified configuration storage adapter for Sanity\n */\nexport class UnifiedConfigStorage {\n private client: SanityClient;\n\n constructor(client: SanityClient) {\n this.client = client;\n }\n\n /**\n * Convert array-based DNT configuration (schema format) to map format (internal use)\n */\n private convertDNTArrayToMap(dntConfigurations?: DNTFieldConfigurationSchema[]): Record<string, Record<string, boolean>> {\n if (!dntConfigurations || !Array.isArray(dntConfigurations)) {\n return {};\n }\n\n const map: Record<string, Record<string, boolean>> = {};\n \n for (const config of dntConfigurations) {\n if (!config.documentType || !config.fields) continue;\n \n map[config.documentType] = {};\n for (const field of config.fields) {\n if (field.fieldPath) {\n map[config.documentType][field.fieldPath] = field.dnt !== false; // Default to true\n }\n }\n }\n \n return map;\n }\n\n /**\n * Convert map-based DNT configuration (internal format) to array format (schema format)\n */\n private convertDNTMapToArray(dntFieldMap?: Record<string, Record<string, boolean>>): DNTFieldConfigurationSchema[] {\n if (!dntFieldMap || typeof dntFieldMap !== 'object') {\n return [];\n }\n\n const array: DNTFieldConfigurationSchema[] = [];\n \n for (const [documentType, fields] of Object.entries(dntFieldMap)) {\n const fieldArray = Object.entries(fields).map(([fieldPath, dnt]) => ({\n _key: `${documentType}-${fieldPath}`.replace(/[^a-zA-Z0-9-_]/g, '-'),\n fieldPath,\n dnt\n }));\n \n array.push({\n documentType,\n fields: fieldArray\n });\n }\n \n return array;\n }\n\n /**\n * Load complete unified configuration from Sanity\n */\n async load(): Promise<UnifiedPluginConfig | null> {\n try {\n const doc = await this.client.fetch<any>(\n `*[_id == $id][0]`,\n { id: UNIFIED_CONFIG_DOC_ID }\n );\n\n if (!doc) {\n console.warn('No unified configuration found in Sanity');\n return null;\n }\n\n // Check for both old (dntFieldMap) and new (dntFieldConfigurations) formats\n let dntFieldMap: Record<string, Record<string, boolean>> = {};\n \n if (doc.dntFieldConfigurations) {\n // New array format - convert to map\n dntFieldMap = this.convertDNTArrayToMap(doc.dntFieldConfigurations);\n } else if (doc.dntFieldMap) {\n // Old map format - use directly (backward compatibility)\n dntFieldMap = doc.dntFieldMap;\n }\n\n // Extract config fields, excluding Sanity metadata\n const config: UnifiedPluginConfig = {\n projectId: doc.projectId,\n accessToken: doc.accessToken,\n translationApiEndpoint: doc.translationApiEndpoint,\n requestContentType: doc.requestContentType,\n responseAcceptHeader: doc.responseAcceptHeader,\n defaultDocumentCreationMode: doc.defaultDocumentCreationMode,\n collisionResolutionMode: doc.collisionResolutionMode || 'replace',\n existingDocumentHandling: doc.existingDocumentHandling || 'draft',\n locales: doc.locales || [],\n defaultLocale: doc.defaultLocale,\n dntFieldMap,\n debugMode: doc.debugMode || false,\n version: doc.version || '1.0.0',\n lastUpdated: doc.lastUpdated\n };\n\n console.log('Loaded unified configuration from Sanity');\n return config;\n } catch (error) {\n console.error('Failed to load unified configuration from Sanity:', error);\n throw error;\n }\n }\n\n /**\n * Save complete unified configuration to Sanity\n */\n async save(config: UnifiedPluginConfig): Promise<void> {\n try {\n // Convert DNT map to array format for schema\n const dntFieldConfigurations = this.convertDNTMapToArray(config.dntFieldMap);\n \n const doc = {\n _id: UNIFIED_CONFIG_DOC_ID,\n _type: UNIFIED_CONFIG_DOC_TYPE,\n projectId: config.projectId,\n accessToken: config.accessToken,\n translationApiEndpoint: config.translationApiEndpoint,\n requestContentType: config.requestContentType,\n responseAcceptHeader: config.responseAcceptHeader,\n defaultDocumentCreationMode: config.defaultDocumentCreationMode,\n collisionResolutionMode: config.collisionResolutionMode,\n existingDocumentHandling: config.existingDocumentHandling,\n locales: config.locales,\n defaultLocale: config.defaultLocale,\n dntFieldConfigurations, // Store in schema format (array)\n debugMode: config.debugMode,\n version: config.version,\n lastUpdated: new Date().toISOString()\n };\n\n await this.client.createOrReplace(doc);\n console.log('Saved unified configuration to Sanity');\n } catch (error) {\n console.error('Failed to save unified configuration to Sanity:', error);\n throw error;\n }\n }\n\n /**\n * Update only specific fields without overwriting entire config\n */\n async update(updates: Partial<UnifiedPluginConfig>): Promise<void> {\n try {\n const current = await this.load() || {};\n const merged = {\n ...current,\n ...updates,\n lastUpdated: new Date().toISOString()\n };\n await this.save(merged);\n } catch (error) {\n console.error('Failed to update unified configuration:', error);\n throw error;\n }\n }\n\n /**\n * Delete the unified configuration document\n */\n async delete(): Promise<void> {\n try {\n await this.client.delete(UNIFIED_CONFIG_DOC_ID);\n console.log('Deleted unified configuration from Sanity');\n } catch (error) {\n console.error('Failed to delete unified configuration from Sanity:', error);\n throw error;\n }\n }\n\n // OAuth-specific methods\n \n /**\n * Load only OAuth configuration\n */\n async loadOAuth(): Promise<OAuthConfig | null> {\n const config = await this.load();\n if (!config || !config.projectId || !config.accessToken) {\n return null;\n }\n return {\n projectId: config.projectId,\n accessToken: config.accessToken\n };\n }\n\n /**\n * Save OAuth configuration\n */\n async saveOAuth(oauthConfig: OAuthConfig): Promise<void> {\n await this.update({\n projectId: oauthConfig.projectId,\n accessToken: oauthConfig.accessToken\n });\n }\n\n // Locale-specific methods\n \n /**\n * Load only locale configuration\n */\n async loadLocale(): Promise<LocaleConfig | null> {\n const config = await this.load();\n if (!config) {\n return null;\n }\n return {\n locales: config.locales || [],\n defaultLocale: config.defaultLocale,\n version: config.version || '1.0.0',\n lastUpdated: config.lastUpdated || new Date().toISOString()\n };\n }\n\n /**\n * Save locale configuration\n */\n async saveLocale(localeConfig: LocaleConfig): Promise<void> {\n await this.update({\n locales: localeConfig.locales,\n defaultLocale: localeConfig.defaultLocale\n });\n }\n\n // DNT-specific methods\n \n /**\n * Get DNT field map for a specific document type\n */\n async getDNTFieldsForType(documentType: string): Promise<Record<string, boolean>> {\n const config = await this.load();\n return config?.dntFieldMap?.[documentType] || {};\n }\n\n /**\n * Set DNT status for a field in a document type\n */\n async setDNTField(documentType: string, fieldPath: string, dnt: boolean): Promise<void> {\n const config = await this.load() || {};\n const dntFieldMap = config.dntFieldMap || {};\n \n if (!dntFieldMap[documentType]) {\n dntFieldMap[documentType] = {};\n }\n \n dntFieldMap[documentType][fieldPath] = dnt;\n \n await this.update({ dntFieldMap });\n }\n\n /**\n * Toggle DNT status for a field in a document type\n */\n async toggleDNTField(documentType: string, fieldPath: string): Promise<boolean> {\n const config = await this.load() || {};\n const dntFieldMap = config.dntFieldMap || {};\n \n if (!dntFieldMap[documentType]) {\n dntFieldMap[documentType] = {};\n }\n \n const currentValue = dntFieldMap[documentType][fieldPath] || false;\n dntFieldMap[documentType][fieldPath] = !currentValue;\n \n await this.update({ dntFieldMap });\n \n return dntFieldMap[documentType][fieldPath];\n }\n\n /**\n * Get DNT status for a specific field in a document type\n */\n async getDNTFieldStatus(documentType: string, fieldPath: string): Promise<boolean> {\n const fields = await this.getDNTFieldsForType(documentType);\n return fields[fieldPath] || false;\n }\n\n /**\n * Clear all DNT fields for a document type\n */\n async clearDNTFieldsForType(documentType: string): Promise<void> {\n const config = await this.load() || {};\n const dntFieldMap = config.dntFieldMap || {};\n \n delete dntFieldMap[documentType];\n \n await this.update({ dntFieldMap });\n }\n\n /**\n * Get all DNT field mappings\n */\n async getAllDNTFields(): Promise<Record<string, Record<string, boolean>>> {\n const config = await this.load();\n return config?.dntFieldMap || {};\n }\n\n // Translation settings methods with fallback defaults\n \n /**\n * Get translation API endpoint with fallback to default\n */\n async getTranslationEndpoint(): Promise<string> {\n const config = await this.load();\n return config?.translationApiEndpoint || 'https://app.easyling.com/_el/ext/direct/sanity';\n }\n\n /**\n * Get request content type with fallback to default\n */\n async getRequestContentType(): Promise<'application/json' | 'application/x-protobuf'> {\n const config = await this.load();\n return config?.requestContentType || 'application/json';\n }\n\n /**\n * Get response accept header with fallback to default\n */\n async getResponseAcceptHeader(): Promise<'application/json' | 'application/x-protobuf'> {\n const config = await this.load();\n return config?.responseAcceptHeader || 'application/json';\n }\n\n /**\n * Get default document creation mode with fallback to default\n */\n async getDefaultDocumentCreationMode(): Promise<'draft' | 'published'> {\n const config = await this.load();\n return config?.defaultDocumentCreationMode || 'draft';\n }\n\n /**\n * Get collision resolution mode with fallback to default ('replace')\n */\n async getCollisionResolutionMode(): Promise<CollisionResolutionMode> {\n const config = await this.load();\n return config?.collisionResolutionMode || 'replace';\n }\n\n /**\n * Get existing document handling mode with fallback to default ('draft')\n * Only applicable when collision resolution mode is 'create'\n */\n async getExistingDocumentHandling(): Promise<ExistingDocumentHandling> {\n const config = await this.load();\n return config?.existingDocumentHandling || 'draft';\n }\n\n /**\n * Get complete collision resolution configuration\n * Returns both the resolution mode and existing document handling settings\n */\n async getCollisionResolutionConfig(): Promise<{\n collisionResolutionMode: CollisionResolutionMode;\n existingDocumentHandling: ExistingDocumentHandling;\n }> {\n const config = await this.load();\n return {\n collisionResolutionMode: config?.collisionResolutionMode || 'replace',\n existingDocumentHandling: config?.existingDocumentHandling || 'draft'\n };\n }\n\n /**\n * Set collision resolution configuration\n */\n async setCollisionResolutionConfig(\n mode: CollisionResolutionMode,\n handling?: ExistingDocumentHandling\n ): Promise<void> {\n const updates: Partial<UnifiedPluginConfig> = {\n collisionResolutionMode: mode\n };\n if (handling !== undefined) {\n updates.existingDocumentHandling = handling;\n }\n await this.update(updates);\n }\n\n /**\n * Get debug mode status\n */\n async getDebugMode(): Promise<boolean> {\n const config = await this.load();\n return config?.debugMode || false;\n }\n\n /**\n * Set debug mode status\n */\n async setDebugMode(enabled: boolean): Promise<void> {\n await this.update({ debugMode: enabled });\n }\n}\n\n","/**\n * DNT Service Manager\n * \n * Provides singleton access to DNTStorageAdapter with proper initialization.\n * Similar to OAuthServiceManager pattern.\n */\n\nimport { SanityClient } from 'sanity';\nimport { DNTStorageAdapter } from './dntStorageAdapter';\nimport { UnifiedConfigStorage } from './unifiedConfigStorage';\n\n/**\n * Singleton manager for DNT storage services\n */\nexport class DNTServiceManager {\n private static instance: DNTServiceManager | null = null;\n private dntStorage: DNTStorageAdapter | null = null;\n private client: SanityClient | null = null;\n\n private constructor() {\n // Private constructor for singleton\n }\n\n /**\n * Get or create the singleton instance\n */\n static getInstance(client?: SanityClient): DNTServiceManager {\n if (!DNTServiceManager.instance) {\n DNTServiceManager.instance = new DNTServiceManager();\n }\n \n if (client && !DNTServiceManager.instance.client) {\n DNTServiceManager.instance.initialize(client);\n }\n \n return DNTServiceManager.instance;\n }\n\n /**\n * Initialize the service with a Sanity client\n */\n initialize(client: SanityClient): void {\n if (this.client && this.dntStorage) {\n // Already initialized\n return;\n }\n\n this.client = client;\n const unifiedStorage = new UnifiedConfigStorage(client);\n this.dntStorage = new DNTStorageAdapter(unifiedStorage);\n \n console.log('DNT Service Manager initialized');\n }\n\n /**\n * Get the DNT storage adapter\n * Throws if not initialized\n */\n getDNTStorage(): DNTStorageAdapter {\n if (!this.dntStorage) {\n throw new Error('DNT Service Manager not initialized. Call initialize() with a SanityClient first.');\n }\n return this.dntStorage;\n }\n\n /**\n * Check if the service is initialized\n */\n isInitialized(): boolean {\n return this.dntStorage !== null;\n }\n\n /**\n * Reset the singleton instance (useful for testing)\n */\n static reset(): void {\n DNTServiceManager.instance = null;\n }\n}\n\n/**\n * Convenience function to get DNT storage adapter\n * Throws if service is not initialized\n */\nexport function getDNTStorage(): DNTStorageAdapter {\n return DNTServiceManager.getInstance().getDNTStorage();\n}\n\n","import { SanityDocument } from 'sanity';\n\n// TranslatableField will be defined in shared/src/types/translation.ts\nexport interface TranslatableField {\n /** The actual field value (serialized as string for the protobuf) */\n value: unknown;\n /** Do Not Translate flag - if true, the field should not be translated */\n dnt?: boolean;\n /** Type of the field value from Sanity (e.g., 'string', 'number', 'date', 'slug', 'array', 'object') */\n type?: string;\n /** \n * GROQ-style path for reconstructing the document structure\n * Example: *[_type == \"blogPost\" && _id == $documentId][0].article.footnotes[_key == \"abc123\"].footnote\n */\n path?: string;\n}\n\n// FieldContext and computeDNTDefault will be in shared/src/utils/dntDefaults.ts\nexport interface FieldContext {\n fieldPath: string;\n fieldName: string;\n fieldType?: string;\n groupName?: string;\n fieldsetName?: string;\n}\n\n// DNT Storage interface for optional dependency injection\nexport interface DNTStorage {\n getFieldsForType(documentType: string): Promise<Record<string, boolean>>;\n}\n\n// Temporary inline implementation of computeDNTDefault until utils are migrated\nfunction computeDNTDefault(context: FieldContext): { shouldBeDNT: boolean; reason: string } {\n const NON_TRANSLATABLE_TYPES = ['date', 'datetime', 'reference', 'image', 'file', 'geopoint', 'number', 'boolean'];\n const DNT_FIELD_NAME_PATTERNS = ['author', 'contributor', 'date', 'time', 'lastModification', 'lastModified', '_key', '_ref', '_type', '_id', '_rev', '_createdAt', '_updatedAt'];\n const DNT_GROUP_NAME_PATTERNS = ['date', 'time'];\n\n if (context.fieldType && NON_TRANSLATABLE_TYPES.includes(context.fieldType)) {\n return { shouldBeDNT: true, reason: `Field type '${context.fieldType}' is non-translatable` };\n }\n\n const fieldNameLower = context.fieldName.toLowerCase();\n for (const pattern of DNT_FIELD_NAME_PATTERNS) {\n if (fieldNameLower.includes(pattern.toLowerCase())) {\n return { shouldBeDNT: true, reason: `Field name contains DNT pattern '${pattern}'` };\n }\n }\n\n if (context.groupName) {\n const groupNameLower = context.groupName.toLowerCase();\n for (const pattern of DNT_GROUP_NAME_PATTERNS) {\n if (groupNameLower.includes(pattern.toLowerCase())) {\n return { shouldBeDNT: true, reason: `Group name contains DNT pattern '${pattern}'` };\n }\n }\n }\n\n if (context.fieldsetName) {\n const fieldsetNameLower = context.fieldsetName.toLowerCase();\n for (const pattern of DNT_GROUP_NAME_PATTERNS) {\n if (fieldsetNameLower.includes(pattern.toLowerCase())) {\n return { shouldBeDNT: true, reason: `Fieldset name contains DNT pattern '${pattern}'` };\n }\n }\n }\n\n return { shouldBeDNT: false, reason: 'No DNT patterns matched' };\n}\n\nexport interface DocumentContent {\n documentId: string;\n title: string;\n htmlContent: string;\n}\n\nexport interface ExtendedDocumentContent extends DocumentContent {\n slug?: string;\n /** Fields can be either flat values or TranslatableField objects with value and dnt properties */\n fields?: Record<string, any>;\n /** Whether the title was found at the document's top level (false if extracted from nested fields) */\n titleFoundAtTopLevel?: boolean;\n /** Whether the body/content was found at the document's top level (false if extracted from nested fields) */\n bodyFoundAtTopLevel?: boolean;\n /** The field name where body content was found (e.g., 'body', 'content', 'text', or nested path) */\n bodyFieldName?: string;\n}\n\nexport interface ExtractedContent {\n documentId: string;\n documentType: string;\n title: string;\n htmlContent: string;\n extractedAt: Date;\n}\n\n/**\n * Atomic Sanity types that should NOT be recursively flattened\n * These are terminal/leaf types that represent single values\n */\nconst ATOMIC_SANITY_TYPES = new Set([\n // Primitive-like types\n 'slug',\n 'date',\n 'datetime',\n \n // Reference types\n 'reference',\n \n // Asset types\n 'image',\n 'file',\n \n // Special content types\n 'geopoint',\n 'color',\n \n // Portable text building blocks (these are processed specially)\n 'block',\n 'span',\n]);\n\n/**\n * Context for document being processed, used to generate GROQ paths\n */\ninterface DocumentContext {\n documentType: string;\n documentId: string;\n}\n\n/**\n * Build a GROQ-style path for field reconstruction\n * \n * @param documentContext - The document type and ID\n * @param fieldPath - The dotted field path (e.g., \"article.footnotes[_key == \\\"abc\\\"].footnote\")\n * @returns GROQ-style path like \"*[_type == \\\"blogPost\\\" && _id == $documentId][0].article.footnotes[_key == \\\"abc\\\"].footnote\"\n */\nfunction buildGroqPath(documentContext: DocumentContext, fieldPath: string): string {\n return `*[_type == \"${documentContext.documentType}\" && _id == $documentId][0].${fieldPath}`;\n}\n\nexport class ContentExtractor {\n /**\n * Infer the Sanity field type from a value\n * \n * @param value - The field value to inspect\n * @returns The inferred Sanity type string\n */\n private inferSanityType(value: unknown): string {\n if (value === null || value === undefined) {\n return 'undefined';\n }\n\n // Check for Sanity-specific object types\n if (typeof value === 'object' && !Array.isArray(value)) {\n const obj = value as any;\n \n // Sanity objects have a _type field\n if (obj._type) {\n return obj._type;\n }\n }\n\n // Check primitive types\n if (typeof value === 'string') {\n return 'string';\n }\n if (typeof value === 'number') {\n return 'number';\n }\n if (typeof value === 'boolean') {\n return 'boolean';\n }\n if (Array.isArray(value)) {\n return 'array';\n }\n if (typeof value === 'object') {\n return 'object';\n }\n\n return 'unknown';\n }\n\n /**\n * Check if a value is an atomic Sanity type that should NOT be recursively flattened\n * These include types like slug, date, datetime, reference, image, file, etc.\n * Custom object types (e.g., articleInfo, footnoteInfo) are NOT atomic and should be flattened\n */\n private isSanitySpecialType(value: unknown): boolean {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n \n const obj = value as any;\n \n // Only atomic Sanity types should be kept intact\n // Custom object types (anything with _type not in ATOMIC_SANITY_TYPES) should be flattened\n if (obj._type && ATOMIC_SANITY_TYPES.has(obj._type)) {\n return true;\n }\n \n return false;\n }\n\n /**\n * Check if an object should be recursively flattened into separate fields\n * Plain objects (fieldsets, custom object types without _type) should be flattened\n * Sanity special types should NOT be flattened\n */\n private shouldFlattenObject(value: unknown): boolean {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n \n // Don't flatten Sanity special types (slug, date, reference, etc.)\n if (this.isSanitySpecialType(value)) {\n return false;\n }\n \n // Plain objects (fieldsets, custom objects) should be flattened\n return true;\n }\n\n /**\n * Recursively flatten a nested object into individual TranslatableField entries\n * Each leaf field gets its own entry with a dotted path key\n * \n * Arrays of objects with _key are flattened with key-based paths like:\n * article.footnotes[_key == \"abc123\"].footnote\n * \n * @param obj - The object to flatten\n * @param basePath - The base path prefix for keys\n * @param fields - The fields record to populate\n * @param docContext - Document context for GROQ path generation\n */\n private flattenObjectToFields(\n obj: Record<string, any>,\n basePath: string,\n fields: Record<string, TranslatableField>,\n docContext: DocumentContext\n ): void {\n for (const [key, value] of Object.entries(obj)) {\n // Skip internal Sanity fields within nested objects\n if (key.startsWith('_')) {\n continue;\n }\n \n const fieldPath = basePath ? `${basePath}.${key}` : key;\n \n if (value === null || value === undefined) {\n continue;\n }\n \n // Handle arrays specially\n if (Array.isArray(value)) {\n this.flattenArrayToFields(value, fieldPath, key, fields, docContext);\n continue;\n }\n \n // Check if this is a custom object type that should be flattened\n // (objects with _type not in ATOMIC_SANITY_TYPES)\n if (typeof value === 'object' && value._type && !ATOMIC_SANITY_TYPES.has(value._type)) {\n // Recursively flatten custom object types\n this.flattenObjectToFields(value, fieldPath, fields, docContext);\n continue;\n }\n \n // Check if this is a nested plain object that should be further flattened\n if (this.shouldFlattenObject(value)) {\n // Recursively flatten nested objects\n this.flattenObjectToFields(value, fieldPath, fields, docContext);\n } else {\n // This is a leaf value (primitive or Sanity special type)\n this.addLeafField(key, value, fieldPath, fields, docContext);\n }\n }\n }\n\n /**\n * Flatten an array into individual TranslatableField entries\n * Arrays of objects with _key get key-based paths\n * \n * @param array - The array to flatten\n * @param fieldPath - The field path for this array\n * @param fieldName - The field name (last segment of path)\n * @param fields - The fields record to populate\n * @param docContext - Document context for GROQ path generation\n */\n private flattenArrayToFields(\n array: any[],\n fieldPath: string,\n fieldName: string,\n fields: Record<string, TranslatableField>,\n docContext: DocumentContext\n ): void {\n // Check if this is portable text (array of blocks)\n if (array.every(item => item && typeof item === 'object' && item._type === 'block')) {\n // Portable text - process as HTML and add as single field\n const extractedValue = this.processArray(fieldName, array);\n const fieldContext: FieldContext = {\n fieldPath,\n fieldName,\n fieldType: 'block'\n };\n const defaultDNT = computeDNTDefault(fieldContext);\n \n fields[fieldPath] = {\n value: extractedValue,\n dnt: defaultDNT.shouldBeDNT,\n type: 'block',\n path: buildGroqPath(docContext, fieldPath)\n };\n return;\n }\n \n // Check if this is an array of references (should be kept as-is)\n if (array.every(item => item && typeof item === 'object' && item._type === 'reference')) {\n fields[fieldPath] = {\n value: JSON.stringify(array),\n dnt: true, // References are always DNT\n type: 'array',\n path: buildGroqPath(docContext, fieldPath)\n };\n return;\n }\n \n // Check if this is an array of keyed objects that should be individually flattened\n const hasKeyedObjects = array.every(item => \n item && typeof item === 'object' && item._key\n );\n \n if (hasKeyedObjects) {\n // Flatten each keyed object with a key-based path\n for (const item of array) {\n const itemPath = `${fieldPath}[_key == \"${item._key}\"]`;\n \n // Check if this item has a _type (custom object type)\n if (item._type && !ATOMIC_SANITY_TYPES.has(item._type)) {\n // Recursively flatten the keyed object\n this.flattenObjectToFields(item, itemPath, fields, docContext);\n } else if (!item._type) {\n // Plain keyed object without _type - flatten its properties\n this.flattenObjectToFields(item, itemPath, fields, docContext);\n } else {\n // Atomic Sanity type - add as-is\n this.addLeafField(fieldName, item, itemPath, fields, docContext);\n }\n }\n return;\n }\n \n // For other arrays (primitives, mixed content, etc.), add as a single field\n const fieldContext: FieldContext = {\n fieldPath,\n fieldName,\n fieldType: 'array'\n };\n const defaultDNT = computeDNTDefault(fieldContext);\n \n fields[fieldPath] = {\n value: JSON.stringify(array),\n dnt: defaultDNT.shouldBeDNT,\n type: 'array',\n path: buildGroqPath(docContext, fieldPath)\n };\n }\n\n /**\n * Add a leaf field (primitive or atomic Sanity type) to the fields record\n */\n private addLeafField(\n fieldName: string,\n value: any,\n fieldPath: string,\n fields: Record<string, TranslatableField>,\n docContext: DocumentContext\n ): void {\n let extractedValue: string;\n let fieldType: string;\n \n if (typeof value === 'object' && value !== null && '_type' in value && value._type === 'slug') {\n extractedValue = (value as any).current || '';\n fieldType = 'slug';\n } else if (typeof value === 'object' && value !== null && '_type' in value && (value._type === 'date' || value._type === 'datetime')) {\n // For date/datetime, extract the value or serialize the object\n const dateValue = (value as any).value || value;\n extractedValue = typeof dateValue === 'string' ? dateValue : JSON.stringify(dateValue);\n fieldType = value._type;\n } else if (typeof value === 'object') {\n // Serialize objects as JSON strings for the protobuf\n extractedValue = JSON.stringify(value);\n fieldType = this.inferSanityType(value);\n } else if (typeof value === 'string') {\n extractedValue = value;\n fieldType = 'string';\n } else {\n // For numbers, booleans, etc., convert to string\n extractedValue = String(value);\n fieldType = this.inferSanityType(value);\n }\n \n // Build field context for default DNT computation\n const fieldContext: FieldContext = {\n fieldPath,\n fieldName,\n fieldType\n };\n \n // Compute default DNT based on field context\n const defaultDNT = computeDNTDefault(fieldContext);\n \n // Add as TranslatableField with GROQ path\n fields[fieldPath] = {\n value: extractedValue,\n dnt: defaultDNT.shouldBeDNT,\n type: fieldType,\n path: buildGroqPath(docContext, fieldPath)\n };\n }\n\n /**\n * Extract content from a single Sanity document and convert to HTML\n */\n async extractDocumentContent(document: SanityDocument): Promise<string> {\n if (!document || !document._id) {\n throw new Error('Invalid document provided');\n }\n\n const htmlContent = this.convertToHtml(document);\n return htmlContent;\n }\n\n /**\n * Convert Sanity document content to HTML format\n */\n convertToHtml(content: any): string {\n if (!content) {\n return '';\n }\n\n let html = '';\n\n // Handle different field types\n for (const [key, value] of Object.entries(content)) {\n // Skip system fields\n if (key.startsWith('_')) {\n continue;\n }\n\n if (value) {\n html += this.processField(key, value);\n }\n }\n\n return html.trim();\n }\n\n /**\n * Extract structured content with separated body, title, slug, and fields\n * Also applies DNT preferences if DNT storage is provided\n * \n * @param document - The Sanity document to extract from\n * @param dntStorage - Optional DNT storage for applying user preferences\n */\n async extractStructuredContent(\n document: SanityDocument,\n dntStorage?: DNTStorage\n ): Promise<ExtendedDocumentContent> {\n if (!document || !document._id) {\n throw new Error('Invalid document provided');\n }\n\n const { title, foundAtTopLevel: titleFoundAtTopLevel } = this.extractTitle(document);\n const slug = this.extractSlug(document);\n const { bodyContent, fields, bodyFoundAtTopLevel, bodyFieldName } = this.separateContentAndFields(document);\n\n // DEBUG: Log extraction results\n console.log('[ContentExtractor] extractStructuredContent:', {\n documentId: document._id,\n documentType: document._type,\n extractedTitle: title,\n titleFoundAtTopLevel,\n bodyFoundAtTopLevel,\n bodyFieldName,\n documentHasTopLevelTitle: 'title' in document,\n documentHasTopLevelBody: 'body' in document || 'content' in document\n });\n\n // Apply DNT preferences from storage based on document type (if storage provided)\n const documentType = document._type || 'document';\n const enhancedFields = await this.applyDNTPreferences(documentType, fields, undefined, dntStorage);\n\n return {\n documentId: document._id,\n title,\n htmlContent: bodyContent,\n slug,\n fields: enhancedFields,\n titleFoundAtTopLevel,\n bodyFoundAtTopLevel,\n bodyFieldName\n };\n }\n\n /**\n * Apply DNT preferences to extracted fields based on document type\n * Now uses document-type-based configuration that applies to all documents of the same type\n * \n * DNT priority:\n * 1. Stored user preference (explicit override) - if dntStorage is provided\n * 2. Default based on field type (slug, date, datetime, reference, etc.)\n * 3. Default based on field name (containing \"author\" or \"contributor\")\n * 4. Default based on group/fieldset name (containing \"date\" or \"time\")\n * 5. Default to translatable (dnt: false)\n * \n * @param documentType - The document type\n * @param fields - The extracted fields\n * @param fieldContextMap - Optional context map for group/fieldset information\n * @param dntStorage - Optional DNT storage for retrieving user preferences\n */\n private async applyDNTPreferences(\n documentType: string, \n fields: Record<string, any>,\n fieldContextMap?: Record<string, { groupName?: string; fieldsetName?: string }>,\n dntStorage?: DNTStorage\n ): Promise<Record<string, any>> {\n try {\n // Get stored DNT field configuration for this document type (if storage provided)\n const storedDntFields = dntStorage \n ? await dntStorage.getFieldsForType(documentType)\n : {};\n\n // Apply DNT preferences to fields (fields already have type information from extraction)\n const enhancedFields: Record<string, TranslatableField> = {};\n \n for (const [fieldPath, fieldValue] of Object.entries(fields)) {\n // Get the field name from the path\n const fieldName = fieldPath.split('.').pop() || fieldPath;\n \n // Get field type from the existing TranslatableField or infer it\n let fieldType: string | undefined;\n if (fieldValue && typeof fieldValue === 'object' && 'type' in fieldValue) {\n fieldType = fieldValue.type;\n }\n \n // Get group/fieldset context if available\n const context = fieldContextMap?.[fieldPath];\n \n // Build field context for DNT computation\n const fieldContext: FieldContext = {\n fieldPath,\n fieldName,\n fieldType,\n groupName: context?.groupName,\n fieldsetName: context?.fieldsetName\n };\n \n // Compute the default DNT status based on field context\n const defaultDNT = computeDNTDefault(fieldContext);\n \n // Check if there's a stored preference for this field (explicit user override)\n const hasStoredPreference = fieldPath in storedDntFields;\n \n // Determine effective DNT:\n // 1. Stored user preference (explicit override) takes highest priority\n // 2. If field was already marked dnt:true during extraction (e.g., reference arrays), preserve it\n // 3. Otherwise use computed default from field context\n const extractionDnt = (fieldValue && typeof fieldValue === 'object' && 'dnt' in fieldValue) ? fieldValue.dnt : undefined;\n const isDNT = hasStoredPreference\n ? storedDntFields[fieldPath]\n : (extractionDnt === true ? true : defaultDNT.shouldBeDNT);\n \n // Fields should already be in TranslatableField format with type set\n if (fieldValue && typeof fieldValue === 'object' && 'value' in fieldValue) {\n const typedField = fieldValue as TranslatableField;\n enhancedFields[fieldPath] = {\n ...typedField,\n dnt: isDNT\n // type is already set from separateContentAndFields()\n };\n } else {\n // Fallback: if for some reason a field isn't wrapped yet, wrap it now\n enhancedFields[fieldPath] = {\n value: fieldValue,\n dnt: isDNT,\n type: this.inferSanityType(fieldValue)\n };\n }\n }\n\n return enhancedFields;\n } catch (error) {\n console.warn(`Failed to apply DNT preferences for document type ${documentType}:`, error);\n // Return original fields if preferences can't be loaded\n return fields;\n }\n }\n\n /**\n * Extract content from multiple documents for bulk operations\n */\n async extractBulkContent(documents: SanityDocument[]): Promise<DocumentContent[]> {\n const results: DocumentContent[] = [];\n\n for (const document of documents) {\n try {\n const htmlContent = await this.extractDocumentContent(document);\n const { title } = this.extractTitle(document);\n\n results.push({\n documentId: document._id,\n title,\n htmlContent\n });\n } catch (error) {\n console.warn(`Failed to extract content from document ${document._id}:`, error);\n // Continue processing other documents\n }\n }\n\n return results;\n }\n\n /**\n * Extract structured content from multiple documents\n * \n * @param documents - Array of Sanity documents to extract from\n * @param dntStorage - Optional DNT storage for applying user preferences\n */\n async extractBulkStructuredContent(\n documents: SanityDocument[],\n dntStorage?: DNTStorage\n ): Promise<ExtendedDocumentContent[]> {\n const results: ExtendedDocumentContent[] = [];\n\n for (const document of documents) {\n try {\n const structuredContent = await this.extractStructuredContent(document, dntStorage);\n results.push(structuredContent);\n } catch (error) {\n console.warn(`Failed to extract structured content from document ${document?._id || 'unknown'}:`, error);\n // Continue processing other documents\n }\n }\n\n return results;\n }\n\n /**\n * Process individual fields based on their type\n */\n private processField(fieldName: string, fieldValue: any): string {\n if (fieldValue === null || fieldValue === undefined) {\n return '';\n }\n\n // Handle arrays (like portable text blocks)\n if (Array.isArray(fieldValue)) {\n return this.processArray(fieldName, fieldValue);\n }\n\n // Handle objects\n if (typeof fieldValue === 'object') {\n return this.processObject(fieldName, fieldValue);\n }\n\n // Handle primitive values\n if (typeof fieldValue === 'string' || typeof fieldValue === 'number') {\n return this.wrapInHtml(fieldName, String(fieldValue));\n }\n\n return '';\n }\n\n /**\n * Process array fields (like portable text blocks)\n */\n private processArray(fieldName: string, array: any[]): string {\n let html = '';\n\n // Check if this is a list structure\n const isListArray = array.every(item => \n item && typeof item === 'object' && item._type === 'block' && \n (item.listItem === 'bullet' || item.listItem === 'number')\n );\n\n if (isListArray) {\n // Handle as a list\n const listType = array[0]?.listItem === 'number' ? 'ol' : 'ul';\n html += `<${listType}>`;\n \n for (const item of array) {\n if (item._type === 'block') {\n const content = this.processPortableTextBlockContent(item);\n html += `<li>${content}</li>`;\n }\n }\n \n html += `</${listType}>`;\n } else {\n // Process as regular array\n for (const item of array) {\n if (item && typeof item === 'object') {\n // Handle portable text blocks\n if (item._type === 'block') {\n html += this.processPortableTextBlock(item);\n } else {\n // Handle other array items\n html += this.processObject(fieldName, item);\n }\n } else {\n // Handle primitive array items\n html += this.wrapInHtml('item', String(item));\n }\n }\n }\n\n return html;\n }\n\n /**\n * Process portable text blocks and convert to HTML\n */\n private processPortableTextBlock(block: any): string {\n const content = this.processPortableTextBlockContent(block);\n \n // Wrap in appropriate HTML tag based on block style\n const style = block.style || 'normal';\n switch (style) {\n case 'h1':\n return `<h1>${content}</h1>`;\n case 'h2':\n return `<h2>${content}</h2>`;\n case 'h3':\n return `<h3>${content}</h3>`;\n case 'h4':\n return `<h4>${content}</h4>`;\n case 'h5':\n return `<h5>${content}</h5>`;\n case 'h6':\n return `<h6>${content}</h6>`;\n case 'blockquote':\n return `<blockquote>${content}</blockquote>`;\n default:\n return `<p>${content}</p>`;\n }\n }\n\n /**\n * Extract content from portable text block children\n */\n private processPortableTextBlockContent(block: any): string {\n if (!block.children || !Array.isArray(block.children)) {\n return '';\n }\n\n let content = '';\n \n // Extract text from children\n for (const child of block.children) {\n if (child._type === 'span' && child.text) {\n let text = child.text;\n \n // Apply formatting marks\n if (child.marks && Array.isArray(child.marks)) {\n for (const mark of child.marks) {\n if (typeof mark === 'string') {\n // Simple marks\n switch (mark) {\n case 'strong':\n text = `<strong>${text}</strong>`;\n break;\n case 'em':\n text = `<em>${text}</em>`;\n break;\n case 'underline':\n text = `<u>${text}</u>`;\n break;\n case 'code':\n text = `<code>${text}</code>`;\n break;\n }\n } else if (typeof mark === 'object' && mark._type === 'link') {\n // Link annotations\n const href = mark.href || '#';\n text = `<a href=\"${this.escapeHtml(href)}\">${text}</a>`;\n }\n }\n }\n \n content += text;\n }\n }\n\n return content;\n }\n\n /**\n * Process object fields\n */\n private processObject(fieldName: string, obj: any): string {\n let html = '';\n\n // Handle references\n if (obj._type === 'reference' && obj._ref) {\n return `<span data-reference=\"${obj._ref}\">Referenced content</span>`;\n }\n\n // Handle images\n if (obj._type === 'image') {\n const alt = obj.alt || 'Image';\n const caption = obj.caption || '';\n return `<figure><img alt=\"${this.escapeHtml(alt)}\" />${caption ? `<figcaption>${this.escapeHtml(caption)}</figcaption>` : ''}</figure>`;\n }\n\n // Handle files\n if (obj._type === 'file') {\n const title = obj.title || 'File';\n return `<a href=\"#\" data-file-ref=\"${obj.asset?._ref || ''}\">${this.escapeHtml(title)}</a>`;\n }\n\n // Handle URLs\n if (obj._type === 'url') {\n const href = obj.href || '#';\n const text = obj.text || href;\n return `<a href=\"${this.escapeHtml(href)}\">${this.escapeHtml(text)}</a>`;\n }\n\n // Handle geopoints\n if (obj._type === 'geopoint') {\n const lat = obj.lat || 0;\n const lng = obj.lng || 0;\n const alt = obj.alt || '';\n return `<span data-geopoint data-lat=\"${lat}\" data-lng=\"${lng}\" ${alt ? `data-alt=\"${alt}\"` : ''}>Location: ${lat}, ${lng}</span>`;\n }\n\n // Handle slugs\n if (obj._type === 'slug') {\n const current = obj.current || '';\n return `<span data-slug=\"${this.escapeHtml(current)}\">${this.escapeHtml(current)}</span>`;\n }\n\n // Handle dates\n if (obj._type === 'date' || obj._type === 'datetime') {\n const dateValue = obj.value || obj;\n if (typeof dateValue === 'string') {\n const date = new Date(dateValue);\n return `<time datetime=\"${dateValue}\">${date.toLocaleDateString()}</time>`;\n }\n }\n\n // Handle color objects\n if (obj._type === 'color') {\n const hex = obj.hex || '#000000';\n const alpha = obj.alpha !== undefined ? obj.alpha : 1;\n return `<span data-color=\"${hex}\" data-alpha=\"${alpha}\" style=\"color: ${hex}\">Color: ${hex}</span>`;\n }\n\n // Handle spans with annotations (links, etc.)\n if (obj._type === 'span' && obj.marks && Array.isArray(obj.marks)) {\n let text = obj.text || '';\n \n // Apply formatting marks\n for (const mark of obj.marks) {\n if (typeof mark === 'string') {\n // Simple marks like 'strong', 'em', etc.\n switch (mark) {\n case 'strong':\n text = `<strong>${text}</strong>`;\n break;\n case 'em':\n text = `<em>${text}</em>`;\n break;\n case 'underline':\n text = `<u>${text}</u>`;\n break;\n case 'code':\n text = `<code>${text}</code>`;\n break;\n }\n } else if (typeof mark === 'object' && mark._type === 'link') {\n // Link annotations\n const href = mark.href || '#';\n text = `<a href=\"${this.escapeHtml(href)}\">${text}</a>`;\n }\n }\n \n return text;\n }\n\n // Handle other objects recursively\n for (const [key, value] of Object.entries(obj)) {\n if (!key.startsWith('_') && value) {\n html += this.processField(key, value);\n }\n }\n\n return html;\n }\n\n /**\n * Wrap content in HTML with field name as class\n */\n private wrapInHtml(fieldName: string, content: string): string {\n const safeFieldName = fieldName.replace(/[^a-zA-Z0-9-_]/g, '');\n return `<div class=\"field-${safeFieldName}\">${this.escapeHtml(content)}</div>`;\n }\n\n /**\n * Separate main content from metadata fields\n * All fields are immediately wrapped in TranslatableField format with type information\n * DNT defaults are computed based on field type and name patterns\n * \n * Complex types (objects/fieldsets) are recursively flattened into individual fields\n * using dotted path notation (e.g., \"metadata.version\", \"metadata.status\")\n */\n private separateContentAndFields(document: SanityDocument): { \n bodyContent: string; \n fields: Record<string, any>;\n bodyFoundAtTopLevel: boolean;\n bodyFieldName: string | undefined;\n } {\n const contentFields = ['body', 'content'];\n const metadataFields = ['title', 'slug', '_id', '_type', '_createdAt', '_updatedAt', '_rev'];\n \n let bodyContent = '';\n let bodyFoundAtTopLevel = false;\n let bodyFieldName: string | undefined;\n const fields: Record<string, TranslatableField> = {};\n \n // Create document context for GROQ path generation\n const docContext: DocumentContext = {\n documentType: document._type || 'document',\n documentId: document._id\n };\n\n // First, try to find body content at top level\n for (const [key, value] of Object.entries(document)) {\n // Skip system fields\n if (key.startsWith('_')) {\n continue;\n }\n\n // Skip title and slug as they're handled separately\n if (key === 'title' || key === 'slug') {\n continue;\n }\n\n if (value) {\n // Check if this is a main content field at top level\n if (contentFields.includes(key)) {\n bodyContent += this.processField(key, value);\n bodyFoundAtTopLevel = true;\n bodyFieldName = key;\n } else {\n // Handle arrays specially\n if (Array.isArray(value)) {\n this.flattenArrayToFields(value, key, key, fields, docContext);\n }\n // Check if this is a custom object type that should be flattened\n else if (typeof value === 'object' && (value as any)._type && !ATOMIC_SANITY_TYPES.has((value as any)._type)) {\n // Recursively flatten custom object types (e.g., articleInfo)\n this.flattenObjectToFields(value as Record<string, any>, key, fields, docContext);\n }\n // Check if this is a plain object that should be recursively flattened\n else if (this.shouldFlattenObject(value)) {\n // Recursively flatten nested objects into individual fields with dotted paths\n this.flattenObjectToFields(value as Record<string, any>, key, fields, docContext);\n } else {\n // Add to fields as TranslatableField with type information\n this.addLeafField(key, value, key, fields, docContext);\n }\n }\n }\n }\n\n // If no main content found at top level, search in nested fields\n if (!bodyContent.trim()) {\n const nestedBody = this.findBodyInNestedFields(document, contentFields);\n if (nestedBody) {\n bodyContent = nestedBody.content;\n bodyFoundAtTopLevel = false;\n bodyFieldName = nestedBody.fieldPath;\n }\n }\n\n // If still no content found, fall back to processing all non-metadata fields\n if (!bodyContent.trim()) {\n for (const [key, value] of Object.entries(document)) {\n if (!key.startsWith('_') && !metadataFields.includes(key) && value) {\n bodyContent += this.processField(key, value);\n }\n }\n // This is a fallback, not a specific body field\n bodyFoundAtTopLevel = false;\n bodyFieldName = undefined;\n }\n\n return { bodyContent: bodyContent.trim(), fields, bodyFoundAtTopLevel, bodyFieldName };\n }\n\n /**\n * Recursively search nested objects and fieldsets for a body/content field\n */\n private findBodyInNestedFields(\n obj: Record<string, any>, \n contentFields: string[],\n basePath: string = ''\n ): { content: string; fieldPath: string } | null {\n for (const [key, value] of Object.entries(obj)) {\n // Skip system/internal fields\n if (key.startsWith('_')) {\n continue;\n }\n\n if (value === null || value === undefined) {\n continue;\n }\n\n const fieldPath = basePath ? `${basePath}.${key}` : key;\n\n // Check if this nested object contains a body field\n if (typeof value === 'object' && !Array.isArray(value)) {\n // Skip atomic Sanity types (slug, reference, image, etc.)\n if (this.isSanitySpecialType(value)) {\n continue;\n }\n\n // Check if this nested object has a body field directly\n for (const contentField of contentFields) {\n if (value[contentField]) {\n const nestedPath = `${fieldPath}.${contentField}`;\n const content = this.processField(contentField, value[contentField]);\n if (content.trim()) {\n return { content, fieldPath: nestedPath };\n }\n }\n }\n\n // Recursively search deeper\n const found = this.findBodyInNestedFields(value, contentFields, fieldPath);\n if (found) {\n return found;\n }\n }\n\n // Also search within arrays of keyed objects\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === 'object' && !this.isSanitySpecialType(item)) {\n // Check if this array item has a body field\n for (const contentField of contentFields) {\n if (item[contentField]) {\n const itemPath = item._key \n ? `${fieldPath}[_key == \"${item._key}\"].${contentField}`\n : `${fieldPath}.${contentField}`;\n const content = this.processField(contentField, item[contentField]);\n if (content.trim()) {\n return { content, fieldPath: itemPath };\n }\n }\n }\n\n // Recursively search deeper in the array item\n const itemBasePath = item._key \n ? `${fieldPath}[_key == \"${item._key}\"]`\n : fieldPath;\n const found = this.findBodyInNestedFields(item, contentFields, itemBasePath);\n if (found) {\n return found;\n }\n }\n }\n }\n }\n\n return null;\n }\n\n /**\n * Extract slug from document\n */\n private extractSlug(document: SanityDocument): string {\n // Check for slug field\n if (document.slug) {\n if (typeof document.slug === 'object' && document.slug !== null && '_type' in document.slug && document.slug._type === 'slug') {\n return (document.slug as any).current || '';\n }\n if (typeof document.slug === 'string') {\n return document.slug;\n }\n }\n\n // Check for other slug-like fields\n const slugFields = ['slug', 'path', 'url', 'permalink'];\n for (const field of slugFields) {\n if (document[field]) {\n if (typeof document[field] === 'object' && document[field] !== null && '_type' in document[field] && (document[field] as any)._type === 'slug') {\n return (document[field] as any).current || '';\n }\n if (typeof document[field] === 'string') {\n return document[field];\n }\n }\n }\n\n return '';\n }\n\n /**\n * Extract title from document\n * Searches top-level fields first, then descends into nested objects/fieldsets\n * @returns Object with title string and flag indicating if found at top level\n */\n private extractTitle(document: SanityDocument): { title: string; foundAtTopLevel: boolean } {\n const titleFields = ['title', 'name', 'heading', 'label'];\n \n // First, try top-level fields\n for (const field of titleFields) {\n if (document[field] && typeof document[field] === 'string') {\n return { title: document[field], foundAtTopLevel: true };\n }\n }\n\n // If not found at top level, search nested objects/fieldsets\n const nestedTitle = this.findTitleInNestedFields(document, titleFields);\n if (nestedTitle) {\n return { title: nestedTitle, foundAtTopLevel: false };\n }\n\n // Fallback to document type and ID\n return { title: `${document._type} (${document._id})`, foundAtTopLevel: false };\n }\n\n /**\n * Recursively search nested objects and fieldsets for a title field\n */\n private findTitleInNestedFields(obj: Record<string, any>, titleFields: string[]): string | null {\n for (const [key, value] of Object.entries(obj)) {\n // Skip system/internal fields\n if (key.startsWith('_')) {\n continue;\n }\n\n if (value === null || value === undefined) {\n continue;\n }\n\n // Check if this nested object contains a title field\n if (typeof value === 'object' && !Array.isArray(value)) {\n // Skip atomic Sanity types (slug, reference, image, etc.)\n if (this.isSanitySpecialType(value)) {\n continue;\n }\n\n // Check if this nested object has a title field directly\n for (const titleField of titleFields) {\n if (value[titleField] && typeof value[titleField] === 'string') {\n return value[titleField];\n }\n }\n\n // Recursively search deeper\n const found = this.findTitleInNestedFields(value, titleFields);\n if (found) {\n return found;\n }\n }\n\n // Also search within arrays of keyed objects (like fieldsets containing objects)\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === 'object' && !this.isSanitySpecialType(item)) {\n // Check if this array item has a title field\n for (const titleField of titleFields) {\n if (item[titleField] && typeof item[titleField] === 'string') {\n return item[titleField];\n }\n }\n\n // Recursively search deeper in the array item\n const found = this.findTitleInNestedFields(item, titleFields);\n if (found) {\n return found;\n }\n }\n }\n }\n }\n\n return null;\n }\n\n /**\n * Escape HTML special characters\n */\n private escapeHtml(text: string): string {\n const htmlEscapeMap: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;'\n };\n return text.replace(/[&<>\"']/g, (char) => htmlEscapeMap[char]);\n }\n}","import { ExtendedDocumentContent } from './contentExtractor';\nimport type {\n TranslatableField,\n TranslationRequest,\n TranslationRequestPayload,\n TranslatedDocument,\n TranslationResponse\n} from '../types/translation';\nimport * as TranslationRequestProto from '@easyling/protos-sanity/dist/generated/translation_request';\nimport * as TranslationResponseProto from '@easyling/protos-sanity/dist/generated/translation_response';\n\n// Re-export types for convenience\nexport type {\n TranslatableField,\n TranslationRequest,\n TranslationRequestPayload,\n TranslatedDocument,\n TranslationResponse\n};\n\nexport interface BulkTranslationSummary {\n totalDocuments: number;\n processedDocuments: number;\n failedDocuments: number;\n requests: TranslationRequest[];\n responses: TranslationResponse[];\n}\n\nexport class TranslationService {\n private placeholderEndpoint: string;\n private accessToken?: string;\n private projectId?: string;\n private requestContentType: 'application/json' | 'application/x-protobuf';\n private responseAcceptHeader: 'application/json' | 'application/x-protobuf';\n\n constructor(\n placeholderEndpoint: string = 'http://localhost:8275/translate',\n requestContentType: 'application/json' | 'application/x-protobuf' = 'application/json',\n responseAcceptHeader: 'application/json' | 'application/x-protobuf' = 'application/json'\n ) {\n this.placeholderEndpoint = placeholderEndpoint;\n this.requestContentType = requestContentType;\n this.responseAcceptHeader = responseAcceptHeader;\n }\n\n /**\n * Infer the Sanity field type from a value\n * \n * @param value - The field value to inspect\n * @returns The inferred Sanity type string\n */\n private inferSanityType(value: unknown): string {\n if (value === null || value === undefined) {\n return 'undefined';\n }\n\n // Check for Sanity-specific object types\n if (typeof value === 'object' && !Array.isArray(value)) {\n const obj = value as any;\n \n // Sanity objects have a _type field\n if (obj._type) {\n return obj._type;\n }\n }\n\n // Check primitive types\n if (typeof value === 'string') {\n return 'string';\n }\n if (typeof value === 'number') {\n return 'number';\n }\n if (typeof value === 'boolean') {\n return 'boolean';\n }\n if (Array.isArray(value)) {\n return 'array';\n }\n if (typeof value === 'object') {\n return 'object';\n }\n\n return 'unknown';\n }\n\n /**\n * Set authentication token and project ID\n * Requirements: 4.1, 4.2, 4.3\n * \n * @param token - Access token for API authentication\n * @param projectId - Project ID to include in requests\n */\n setAuthToken(token: string, projectId: string): void {\n this.accessToken = token;\n this.projectId = projectId;\n }\n\n /**\n * Clear authentication data\n */\n clearAuth(): void {\n this.accessToken = undefined;\n this.projectId = undefined;\n }\n\n /**\n * Update configuration for content types and endpoint\n * Allows partial updates - only provided parameters will be updated\n * Requirements: 1.1, 2.3, 3.3\n * \n * @param endpoint - Optional translation API endpoint URL\n * @param requestContentType - Optional request Content-Type header value\n * @param responseAcceptHeader - Optional response Accept header value\n */\n setConfiguration(\n endpoint?: string,\n requestContentType?: 'application/json' | 'application/x-protobuf',\n responseAcceptHeader?: 'application/json' | 'application/x-protobuf'\n ): void {\n if (endpoint !== undefined) {\n this.placeholderEndpoint = endpoint;\n }\n if (requestContentType !== undefined) {\n this.requestContentType = requestContentType;\n }\n if (responseAcceptHeader !== undefined) {\n this.responseAcceptHeader = responseAcceptHeader;\n }\n }\n\n /**\n * Convert internal payload to Protocol Buffer binary format\n * Requirements: Uses @easyling/sanity protobuf library\n * \n * @param payload - Internal translation request payload\n * @returns Binary protobuf message\n */\n private convertPayloadToProtobuf(payload: TranslationRequestPayload): Uint8Array {\n // Convert internal TranslatableField objects to protobuf format\n // Type information should be set by this point (from contentExtractor)\n const protoFields: { [key: string]: TranslationRequestProto.TranslatableField } = {};\n for (const [key, field] of Object.entries(payload.content.fields)) {\n // Handle both TranslatableField objects and plain values (for backward compatibility)\n if (field && typeof field === 'object' && 'value' in field) {\n // Already a TranslatableField object - type should be set from contentExtractor\n const typedField = field as TranslatableField;\n \n // Warn if type is missing - should be set by contentExtractor in normal flow\n let fieldType = typedField.type;\n if (!fieldType) {\n console.warn(`Field '${key}' missing type in protobuf conversion, inferring from value`);\n fieldType = this.inferSanityType(typedField.value);\n }\n \n protoFields[key] = {\n value: typeof typedField.value === 'string' ? typedField.value : JSON.stringify(typedField.value),\n dnt: typedField.dnt || false,\n type: fieldType,\n path: (typedField as { path?: string }).path ?? key\n };\n } else {\n // Plain value - may happen for direct API calls that bypass contentExtractor\n console.warn(`Field '${key}' not in TranslatableField format, wrapping with inferred type`);\n protoFields[key] = {\n value: typeof field === 'string' ? field : JSON.stringify(field),\n dnt: false,\n type: this.inferSanityType(field),\n path: key\n };\n }\n }\n\n // Create protobuf message from our payload\n const protoPayload = TranslationRequestProto.TranslationRequestPayload.create({\n content: {\n body: payload.content.body,\n title: payload.content.title,\n slug: payload.content.slug,\n fields: protoFields\n },\n project: this.projectId || '', // Project code for identification\n format: payload.format,\n metadata: {\n documentId: payload.metadata.documentId,\n documentType: payload.metadata.documentType,\n title: payload.metadata.title,\n sourceLanguage: payload.metadata.sourceLanguage || '',\n targetLanguage: payload.metadata.targetLanguage || '',\n targetLocales: payload.metadata.targetLocales || []\n }\n });\n\n // Encode protobuf message to binary format\n return TranslationRequestProto.TranslationRequestPayload.encode(protoPayload).finish();\n }\n\n /**\n * Convert protobuf payload to JSON for logging purposes only\n * \n * @param payload - Internal translation request payload\n * @returns JSON representation for logging\n */\n private convertPayloadToProtobufJSON(payload: TranslationRequestPayload): unknown {\n // Convert internal TranslatableField objects to protobuf format\n const protoFields: { [key: string]: TranslationRequestProto.TranslatableField } = {};\n for (const [key, field] of Object.entries(payload.content.fields)) {\n if (field && typeof field === 'object' && 'value' in field) {\n const typedField = field as TranslatableField;\n protoFields[key] = {\n value: typeof typedField.value === 'string' ? typedField.value : JSON.stringify(typedField.value),\n dnt: typedField.dnt || false,\n type: typedField.type || 'unknown',\n path: (typedField as { path?: string }).path ?? key\n };\n } else {\n protoFields[key] = {\n value: typeof field === 'string' ? field : JSON.stringify(field),\n dnt: false,\n type: 'unknown',\n path: key\n };\n }\n }\n\n const protoPayload = TranslationRequestProto.TranslationRequestPayload.create({\n content: {\n body: payload.content.body,\n title: payload.content.title,\n slug: payload.content.slug,\n fields: protoFields\n },\n project: this.projectId || '',\n format: payload.format,\n metadata: {\n documentId: payload.metadata.documentId,\n documentType: payload.metadata.documentType,\n title: payload.metadata.title,\n sourceLanguage: payload.metadata.sourceLanguage || '',\n targetLanguage: payload.metadata.targetLanguage || '',\n targetLocales: payload.metadata.targetLocales || []\n }\n });\n\n return TranslationRequestProto.TranslationRequestPayload.toJSON(protoPayload);\n }\n\n /**\n * Normalize field values to ensure consistency\n * Extracts values from TranslatableField objects and handles various formats\n */\n private normalizeTranslatedFields(fields: Record<string, any>): Record<string, TranslatableField> {\n const normalizedFields: Record<string, TranslatableField> = {};\n \n if (!fields || typeof fields !== 'object') {\n return normalizedFields;\n }\n \n for (const [key, fieldValue] of Object.entries(fields)) {\n // Handle both TranslatableField objects and plain values\n if (fieldValue && typeof fieldValue === 'object' && 'value' in fieldValue) {\n // It's already a TranslatableField object\n normalizedFields[key] = {\n value: fieldValue.value,\n dnt: fieldValue.dnt || false,\n type: fieldValue.type || this.inferSanityType(fieldValue.value)\n };\n } else {\n // It's a plain value - wrap it in TranslatableField format\n normalizedFields[key] = {\n value: fieldValue,\n dnt: false,\n type: this.inferSanityType(fieldValue)\n };\n }\n }\n \n return normalizedFields;\n }\n\n /**\n * Convert binary protobuf response to internal format\n * Requirements: Uses @easyling/sanity protobuf library\n * \n * @param binaryData - Binary protobuf response data\n * @returns Internal translation response format\n */\n private convertProtobufBinaryToResponse(binaryData: Uint8Array): TranslationResponse {\n // Decode binary protobuf response\n const protoResponse = TranslationResponseProto.TranslationResponse.decode(binaryData);\n\n // Convert to internal format\n const translatedDocuments: TranslatedDocument[] = protoResponse.translatedDocuments.map(doc => {\n // Convert protobuf TranslatableField back to internal format\n const fields: Record<string, TranslatableField> = {};\n \n if (doc.fields && typeof doc.fields === 'object') {\n for (const [key, protoField] of Object.entries(doc.fields)) {\n if (protoField && typeof protoField === 'object' && 'value' in protoField) {\n const fieldValue = (protoField as any).value;\n const fieldType = (protoField as any).type;\n \n try {\n // Try to parse as JSON if it's a stringified value\n const parsedValue = JSON.parse(fieldValue);\n fields[key] = {\n value: parsedValue,\n dnt: (protoField as any).dnt || false,\n type: fieldType || this.inferSanityType(parsedValue)\n };\n } catch {\n // If parsing fails, use the string value as-is\n fields[key] = {\n value: fieldValue,\n dnt: (protoField as any).dnt || false,\n type: fieldType || this.inferSanityType(fieldValue)\n };\n }\n }\n }\n }\n\n return {\n body: doc.body,\n title: doc.title,\n slug: doc.slug,\n fields,\n locale: doc.locale\n };\n });\n\n return {\n success: protoResponse.success,\n translatedDocuments,\n sourceLocale: protoResponse.sourceLocale,\n error: protoResponse.error,\n requestId: protoResponse.requestId\n };\n }\n\n /**\n * Convert protobuf JSON response back to internal format (for legacy support)\n * Requirements: Uses @easyling/sanity protobuf library\n * \n * @param jsonData - JSON response data\n * @returns Internal translation response format\n */\n private convertProtobufJSONToResponse(jsonData: any): TranslationResponse {\n // Parse the JSON into a protobuf message\n const protoResponse = TranslationResponseProto.TranslationResponse.fromJSON(jsonData);\n\n // Convert to internal format\n const translatedDocuments: TranslatedDocument[] = protoResponse.translatedDocuments.map((doc, index) => {\n // Get original document data from jsonData to handle mixed field formats\n const originalDoc = jsonData.translatedDocuments?.[index];\n \n // Convert protobuf TranslatableField back to internal format\n const protoFields: Record<string, any> = {};\n \n if (doc.fields && typeof doc.fields === 'object') {\n for (const [key, protoField] of Object.entries(doc.fields)) {\n // Get the original value from jsonData to check if protobuf lost it\n const originalValue = originalDoc?.fields?.[key];\n \n // Handle protobuf field format\n if (protoField && typeof protoField === 'object' && 'value' in protoField) {\n const fieldValue = (protoField as any).value;\n const fieldType = (protoField as any).type;\n \n // Check if protobuf parsing lost the value (empty string when original had value)\n if ((fieldValue === '' || fieldValue === undefined) && originalValue !== undefined && originalValue !== '') {\n // Use original value instead\n protoFields[key] = originalValue;\n } else {\n try {\n // Try to parse as JSON if it's a stringified value\n const parsedValue = JSON.parse(fieldValue);\n protoFields[key] = {\n value: parsedValue,\n dnt: (protoField as any).dnt || false,\n type: fieldType || this.inferSanityType(parsedValue)\n };\n } catch {\n // If parsing fails, use the string value as-is\n protoFields[key] = {\n value: fieldValue,\n dnt: (protoField as any).dnt || false,\n type: fieldType || this.inferSanityType(fieldValue)\n };\n }\n }\n } else {\n // Plain value - but protobuf parsing might have lost it\n // Fall back to original JSON data if the value is empty/undefined\n if (originalValue !== undefined && (!protoField || protoField === '')) {\n protoFields[key] = originalValue;\n } else {\n protoFields[key] = protoField;\n }\n }\n }\n }\n \n // Also check for fields in original data that might have been lost in protobuf conversion\n if (originalDoc?.fields && typeof originalDoc.fields === 'object') {\n for (const [key, originalValue] of Object.entries(originalDoc.fields)) {\n if (!(key in protoFields)) {\n protoFields[key] = originalValue;\n }\n }\n }\n\n // Normalize the fields to ensure consistent format\n const fields = this.normalizeTranslatedFields(protoFields);\n\n return {\n body: doc.body,\n title: doc.title,\n slug: doc.slug,\n fields,\n locale: doc.locale\n };\n });\n\n return {\n success: protoResponse.success,\n translatedDocuments,\n sourceLocale: protoResponse.sourceLocale,\n error: protoResponse.error,\n requestId: protoResponse.requestId\n };\n }\n\n /**\n * Prepare a translation request for a single document\n * Requirements: 1.2, 1.3, 3.3, 2.5, 2.7\n * \n * @param content - Document content to translate\n * @param documentType - Type of the document\n * @param sourceLanguage - Source language code (optional)\n * @param targetLanguage - Single target language code (optional, for backward compatibility)\n * @param targetLocales - Array of target locale codes (optional, for multi-locale support)\n */\n prepareTranslationRequest(\n content: ExtendedDocumentContent,\n documentType: string = 'document',\n sourceLanguage?: string,\n targetLanguage?: string,\n targetLocales?: string[]\n ): TranslationRequest {\n if (!content || !content.documentId || !content.htmlContent) {\n throw new Error('Invalid document content provided');\n }\n\n // Convert flat fields to TranslatableField objects and ensure type is ALWAYS set\n const translatableFields: Record<string, TranslatableField> = {};\n if (content.fields) {\n for (const [key, value] of Object.entries(content.fields)) {\n // If the field is already in the new format, ensure type is set\n if (value && typeof value === 'object' && 'value' in value) {\n const typedField = value as TranslatableField;\n // Type should already be set from contentExtractor, but ensure it's never undefined\n if (!typedField.type) {\n console.warn(`Field '${key}' missing type, inferring from value`);\n }\n translatableFields[key] = {\n ...typedField,\n type: typedField.type || this.inferSanityType(typedField.value)\n };\n } else {\n // Convert flat field to TranslatableField object (should rarely happen)\n console.warn(`Field '${key}' not in TranslatableField format, converting`);\n translatableFields[key] = {\n value,\n dnt: false,\n type: this.inferSanityType(value)\n };\n }\n }\n }\n\n // DEBUG: Log titleFoundAtTopLevel from content\n console.log('[TranslationService] prepareTranslationRequest - titleFoundAtTopLevel:', {\n fromContent: content.titleFoundAtTopLevel,\n willUse: content.titleFoundAtTopLevel ?? true\n });\n\n const payload: TranslationRequestPayload = {\n content: {\n body: content.htmlContent,\n title: content.title || `Document ${content.documentId}`,\n slug: content.slug || '',\n fields: translatableFields\n },\n format: 'html',\n metadata: {\n documentId: content.documentId,\n documentType,\n title: content.title || `Document ${content.documentId}`,\n ...(sourceLanguage && { sourceLanguage }),\n // Support both single targetLanguage (backward compatibility) and targetLocales array\n ...(targetLanguage && { targetLanguage }),\n ...(targetLocales && targetLocales.length > 0 && { targetLocales }),\n // Track whether title was found at top level for document creation\n titleFoundAtTopLevel: content.titleFoundAtTopLevel ?? true\n }\n };\n\n return {\n documentId: content.documentId,\n endpoint: this.placeholderEndpoint,\n payload\n };\n }\n\n /**\n * Translate a single document\n * Requirements: 1.2, 1.3, 3.3, 2.5, 2.7\n * \n * @param content - Document content to translate\n * @param documentType - Type of the document\n * @param sourceLanguage - Source language code (optional)\n * @param targetLanguage - Single target language code (optional, for backward compatibility)\n * @param targetLocales - Array of target locale codes (optional, for multi-locale support)\n */\n async translateDocument(\n content: ExtendedDocumentContent,\n documentType: string = 'document',\n sourceLanguage?: string,\n targetLanguage?: string,\n targetLocales?: string[]\n ): Promise<TranslationResponse> {\n const request = this.prepareTranslationRequest(\n content, \n documentType, \n sourceLanguage, \n targetLanguage,\n targetLocales\n );\n return this.sendTranslationRequest(request);\n }\n\n /**\n * Send translation request to the configured endpoint\n * \n * Uses the @easyling/sanity Protocol Buffer library to format messages as JSON\n * (not binary protobuf) for better compatibility with various backends.\n * Handles the new array-based response format with backward compatibility.\n * The service now expects translatedDocuments as an array, but will convert\n * legacy formats (translatedContent or translations object) to the new format.\n * \n * Supports dual mode operation:\n * - Authenticated mode: Uses Bearer token authentication when configured\n * - Legacy mode: Works without authentication for backward compatibility\n */\n async sendTranslationRequest(request: TranslationRequest): Promise<TranslationResponse> {\n try {\n this.logTranslationRequest(request);\n\n // Build headers with configured content types\n // Requirements: 2.2, 2.3, 3.2, 3.3\n const headers: Record<string, string> = {\n 'Content-Type': this.requestContentType,\n 'Accept': this.responseAcceptHeader\n };\n\n // Add Authorization header if access token is available\n if (this.accessToken) {\n headers['Authorization'] = `Bearer ${this.accessToken}`;\n }\n\n // Serialize payload based on configured content type\n // Requirements: 2.2, 2.3\n let body: string | ArrayBuffer | Uint8Array;\n if (this.requestContentType === 'application/x-protobuf') {\n // Use binary protobuf serialization\n body = this.convertPayloadToProtobuf(request.payload);\n } else {\n // Use JSON serialization (protobuf JSON format)\n const protobufJSON = this.convertPayloadToProtobufJSON(request.payload);\n body = JSON.stringify(protobufJSON);\n }\n\n const response = await fetch(request.endpoint, {\n method: 'POST',\n headers,\n body: body as any // TypeScript fetch types are strict, but Uint8Array is valid\n });\n\n if (!response.ok) {\n // Handle 401 Unauthorized\n if (response.status === 401) {\n return {\n success: false,\n error: 'Authentication failed. Please check your access token in the Easyling Configuration.'\n };\n }\n \n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n // Parse response based on configured Accept header\n // Requirements: 3.2, 3.3, 3.5\n if (this.responseAcceptHeader === 'application/x-protobuf') {\n // Parse binary protobuf response\n const arrayBuffer = await response.arrayBuffer();\n const binaryData = new Uint8Array(arrayBuffer);\n return this.convertProtobufBinaryToResponse(binaryData);\n }\n\n // Parse JSON response\n const data = await response.json();\n\n // Try to parse as protobuf JSON format first\n try {\n // If the response has the expected protobuf structure, parse it\n if (data.success !== undefined && (data.translatedDocuments || data.error)) {\n return this.convertProtobufJSONToResponse(data);\n }\n } catch (protoError) {\n console.warn('Failed to parse response as protobuf format, falling back to legacy handling:', protoError);\n }\n\n // New format: translatedDocuments array (without success field - for backward compatibility)\n if (data.translatedDocuments && Array.isArray(data.translatedDocuments)) {\n // Normalize fields in each translated document to ensure consistency\n const normalizedDocuments = data.translatedDocuments.map((doc: any) => ({\n ...doc,\n fields: this.normalizeTranslatedFields(doc.fields || {})\n }));\n \n return {\n success: true,\n translatedDocuments: normalizedDocuments,\n sourceLocale: data.sourceLocale,\n requestId: data.requestId\n };\n }\n\n // Backward compatibility: translations object (convert to array)\n if (data.translations) {\n const translatedDocuments: TranslatedDocument[] = [];\n for (const [locale, translation] of Object.entries(data.translations)) {\n if (translation && typeof translation === 'object' && 'content' in translation) {\n const content = translation.content as TranslatedDocument;\n // Normalize fields to ensure consistency\n translatedDocuments.push({\n ...content,\n fields: this.normalizeTranslatedFields(content.fields || {}),\n locale\n });\n }\n }\n return {\n success: true,\n translatedDocuments,\n sourceLocale: data.sourceLocale,\n requestId: data.requestId,\n // Keep deprecated field for backward compatibility\n translations: data.translations\n };\n }\n\n // Backward compatibility: single translatedContent object (convert to array)\n if (data.translatedContent) {\n const targetLocale = request.payload.metadata.targetLanguage || \n request.payload.metadata.targetLocales?.[0];\n // Normalize fields to ensure consistency\n const normalizedContent = {\n ...data.translatedContent,\n fields: this.normalizeTranslatedFields(data.translatedContent.fields || {}),\n locale: targetLocale\n };\n \n return {\n success: true,\n translatedDocuments: [normalizedContent],\n sourceLocale: request.payload.metadata.sourceLanguage,\n requestId: data.requestId,\n // Keep deprecated field for backward compatibility\n translatedContent: data.translatedContent\n };\n }\n\n // Fallback: treat data.content as translatedContent\n if (data.content) {\n const targetLocale = request.payload.metadata.targetLanguage || \n request.payload.metadata.targetLocales?.[0];\n // Normalize fields to ensure consistency\n const normalizedContent = {\n ...data.content,\n fields: this.normalizeTranslatedFields(data.content.fields || {}),\n locale: targetLocale\n };\n \n return {\n success: true,\n translatedDocuments: [normalizedContent],\n sourceLocale: request.payload.metadata.sourceLanguage,\n requestId: data.requestId,\n // Keep deprecated field for backward compatibility\n translatedContent: data.content\n };\n }\n\n throw new Error('Invalid response format: missing translatedDocuments, translations, or translatedContent');\n\n } catch (error) {\n console.error(`Translation request failed for document ${request.documentId}:`, error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error occurred'\n };\n }\n }\n\n /**\n * Log translation request to console for verification\n * Requirements: 1.3, 2.4\n */\n logTranslationRequest(request: TranslationRequest): void {\n console.log('Translation Request:', {\n timestamp: new Date().toISOString(),\n documentId: request.documentId,\n endpoint: request.endpoint,\n payload: request.payload\n });\n }\n /**\n * Process bulk translation for multiple documents\n * Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.7\n * \n * @param contents - Array of document contents to translate\n * @param documentType - Type of the documents\n * @param sourceLanguage - Source language code (optional)\n * @param targetLanguage - Single target language code (optional, for backward compatibility)\n * @param targetLocales - Array of target locale codes (optional, for multi-locale support)\n */\n async processBulkTranslation(\n contents: ExtendedDocumentContent[],\n documentType: string = 'document',\n sourceLanguage?: string,\n targetLanguage?: string,\n targetLocales?: string[]\n ): Promise<BulkTranslationSummary> {\n const summary: BulkTranslationSummary = {\n totalDocuments: contents.length,\n processedDocuments: 0,\n failedDocuments: 0,\n requests: [],\n responses: []\n };\n\n const localeCount = targetLocales?.length || 1;\n console.log(`Starting bulk translation for ${contents.length} documents to ${localeCount} locale(s)`);\n\n for (const content of contents) {\n try {\n // Prepare translation request for each document\n const request = this.prepareTranslationRequest(\n content,\n documentType,\n sourceLanguage,\n targetLanguage,\n targetLocales\n );\n\n // Send the translation request\n const response = await this.sendTranslationRequest(request);\n\n // Add to summary\n summary.requests.push(request);\n summary.responses.push(response);\n\n if (response.success) {\n summary.processedDocuments++;\n } else {\n summary.failedDocuments++;\n }\n\n } catch (error) {\n console.error(`Failed to process document ${content.documentId}:`, error);\n summary.failedDocuments++;\n summary.responses.push({\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error occurred'\n });\n }\n }\n\n // Log bulk operation summary\n this.logBulkTranslationSummary(summary);\n\n return summary;\n }\n\n /**\n * Log bulk translation summary\n * Requirements: 2.5\n */\n private logBulkTranslationSummary(summary: BulkTranslationSummary): void {\n console.log('Bulk Translation Summary:', {\n timestamp: new Date().toISOString(),\n totalDocuments: summary.totalDocuments,\n processedDocuments: summary.processedDocuments,\n failedDocuments: summary.failedDocuments,\n successRate: summary.totalDocuments > 0\n ? ((summary.processedDocuments / summary.totalDocuments) * 100).toFixed(2) + '%'\n : '0%'\n });\n }\n\n /**\n * Update the placeholder endpoint\n */\n setEndpoint(endpoint: string): void {\n this.placeholderEndpoint = endpoint;\n }\n\n /**\n * Get the current endpoint\n */\n getEndpoint(): string {\n return this.placeholderEndpoint;\n }\n}","/**\n * Collision Detection Service\n * Requirements: Translation Collision Handling - EARS 2.1, 2.2\n * \n * Detects existing translated documents for the same source document and target locale\n * to enable collision resolution handling.\n */\n\nimport { SanityClient, SanityDocument } from 'sanity';\n\n/**\n * Result of a collision detection check\n */\nexport interface CollisionResult {\n /** Whether a collision was detected */\n detected: boolean;\n /** The existing translated document if collision was detected */\n existingDocument?: SanityDocument;\n /** How the collision was identified */\n matchedBy?: 'parent' | 'slug-locale';\n}\n\n/**\n * Options for collision detection\n */\nexport interface CollisionDetectionOptions {\n /** The source document ID (the original document being translated) */\n sourceDocumentId: string;\n /** The target locale code for the translation */\n targetLocale: string;\n /** The slug of the translated document (optional, used for slug-locale matching) */\n slug?: string;\n /** The document type to search within */\n documentType?: string;\n}\n\n/**\n * Error type for collision detection operations\n */\nexport class CollisionDetectionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: unknown\n ) {\n super(message);\n this.name = 'CollisionDetectionError';\n }\n}\n\n/**\n * Service for detecting translation collisions\n * \n * A collision occurs when a translated document already exists for the same\n * source document and target locale. The service identifies collisions using:\n * 1. Parent reference matching: parentDocument._ref == sourceDocumentId AND locale == targetLocale\n * 2. Slug-locale matching: slug.current == slug AND locale == targetLocale\n */\nexport class CollisionDetectionService {\n private client: SanityClient;\n\n constructor(client: SanityClient) {\n this.client = client;\n }\n\n /**\n * Detect if a collision exists for the given source document and target locale\n * \n * @param options - Options specifying the source document, target locale, and optional slug\n * @returns CollisionResult indicating whether a collision was found and details\n */\n async detectCollision(options: CollisionDetectionOptions): Promise<CollisionResult> {\n const { sourceDocumentId, targetLocale, slug, documentType } = options;\n\n if (!sourceDocumentId || !targetLocale) {\n throw new CollisionDetectionError(\n 'sourceDocumentId and targetLocale are required',\n 'INVALID_OPTIONS'\n );\n }\n\n // Strip drafts. prefix if present for consistent matching\n const cleanSourceId = sourceDocumentId.replace(/^drafts\\./, '');\n\n try {\n // First, check by parent reference\n const parentMatch = await this.findByParentReference(cleanSourceId, targetLocale, documentType);\n if (parentMatch) {\n console.log(`[CollisionDetection] Found collision by parent reference: ${parentMatch._id}`);\n return {\n detected: true,\n existingDocument: parentMatch,\n matchedBy: 'parent'\n };\n }\n\n // If no parent match and slug is provided, check by slug + locale\n if (slug) {\n const slugMatch = await this.findBySlugAndLocale(slug, targetLocale, documentType);\n if (slugMatch) {\n console.log(`[CollisionDetection] Found collision by slug-locale: ${slugMatch._id}`);\n return {\n detected: true,\n existingDocument: slugMatch,\n matchedBy: 'slug-locale'\n };\n }\n }\n\n // No collision found\n console.log(`[CollisionDetection] No collision detected for source ${cleanSourceId}, locale ${targetLocale}`);\n return {\n detected: false\n };\n\n } catch (error) {\n console.error('[CollisionDetection] Error during collision detection:', error);\n throw new CollisionDetectionError(\n 'Failed to detect collision',\n 'DETECTION_FAILED',\n error\n );\n }\n }\n\n /**\n * Find an existing document by parent reference and locale\n * \n * @param sourceDocumentId - The ID of the source/parent document\n * @param targetLocale - The target locale code\n * @param documentType - Optional document type to filter by\n */\n private async findByParentReference(\n sourceDocumentId: string,\n targetLocale: string,\n documentType?: string\n ): Promise<SanityDocument | null> {\n // Build query to find documents with matching parent reference and locale\n // Handle both drafts and published versions by checking both ID patterns\n // Also handle cases where locale is null but encoded in the document ID\n const typeFilter = documentType ? `&& _type == $documentType` : '';\n \n // First, try to find with explicit locale field\n const queryWithLocale = `*[\n (\n parentDocument._ref == $sourceId ||\n parentDocument._ref == $sourceIdWithDrafts\n ) &&\n (\n locale == $targetLocale ||\n locale.value == $targetLocale\n )\n ${typeFilter}\n ][0]`;\n\n // Fallback: Find by parent ref and locale pattern in document ID\n // Pattern: {sourceId}-{locale}-{timestamp} e.g., \"abc123-ja-JP-1234567890\"\n const queryWithIdPattern = `*[\n (\n parentDocument._ref == $sourceId ||\n parentDocument._ref == $sourceIdWithDrafts\n ) &&\n _id match $idPattern\n ${typeFilter}\n ][0]`;\n\n const params: Record<string, string> = {\n sourceId: sourceDocumentId,\n sourceIdWithDrafts: `drafts.${sourceDocumentId}`,\n targetLocale,\n idPattern: `*-${targetLocale}-*`\n };\n\n if (documentType) {\n params.documentType = documentType;\n }\n\n // Try with explicit locale field first\n let result = await this.client.fetch(queryWithLocale, params);\n \n // If not found, try with ID pattern matching\n if (!result) {\n result = await this.client.fetch(queryWithIdPattern, params);\n }\n \n return result || null;\n }\n\n /**\n * Find an existing document by slug and locale\n * \n * @param slug - The document slug to match\n * @param targetLocale - The target locale code\n * @param documentType - Optional document type to filter by\n */\n private async findBySlugAndLocale(\n slug: string,\n targetLocale: string,\n documentType?: string\n ): Promise<SanityDocument | null> {\n const typeFilter = documentType ? `&& _type == $documentType` : '';\n \n // Query for documents with matching slug and locale (explicit locale field)\n const queryWithLocale = `*[\n (\n slug == $slug ||\n slug.current == $slug\n ) &&\n (\n locale == $targetLocale ||\n locale.value == $targetLocale\n )\n ${typeFilter}\n ][0]`;\n\n // Fallback: Find by slug match and locale pattern in document ID\n // This handles documents where locale is null but encoded in the ID\n const queryWithIdPattern = `*[\n (\n slug == $slug ||\n slug.current == $slug\n ) &&\n _id match $idPattern\n ${typeFilter}\n ][0]`;\n\n const params: Record<string, string> = {\n slug,\n targetLocale,\n idPattern: `*-${targetLocale}-*`\n };\n\n if (documentType) {\n params.documentType = documentType;\n }\n\n // Try with explicit locale field first\n let result = await this.client.fetch(queryWithLocale, params);\n \n // If not found, try with ID pattern matching\n if (!result) {\n result = await this.client.fetch(queryWithIdPattern, params);\n }\n\n return result || null;\n }\n\n /**\n * Check if multiple collisions exist for bulk translation operations\n * \n * @param sourceDocumentId - The source document being translated\n * @param targetLocales - Array of target locale codes\n * @param slug - Optional slug for slug-locale matching\n * @param documentType - Optional document type to filter by\n * @returns Map of locale code to collision result\n */\n async detectBulkCollisions(\n sourceDocumentId: string,\n targetLocales: string[],\n slug?: string,\n documentType?: string\n ): Promise<Map<string, CollisionResult>> {\n const results = new Map<string, CollisionResult>();\n\n // Process each locale\n for (const targetLocale of targetLocales) {\n try {\n const result = await this.detectCollision({\n sourceDocumentId,\n targetLocale,\n slug,\n documentType\n });\n results.set(targetLocale, result);\n } catch (error) {\n console.error(`[CollisionDetection] Error checking locale ${targetLocale}:`, error);\n // Set as no collision detected but log the error\n results.set(targetLocale, { detected: false });\n }\n }\n\n return results;\n }\n}\n","import { SanityDocument, SanityClient } from 'sanity';\nimport { TranslationResponse } from './translationService';\nimport { CollisionDetectionService, CollisionResult } from './collisionDetectionService';\nimport { CollisionResolutionMode, ExistingDocumentHandling } from '../types';\n\n/**\n * Options for document creation from translation\n */\nexport interface DocumentCreationOptions {\n /** Target language code for the translated document */\n targetLanguage?: string;\n /** Source language code of the original document */\n sourceLanguage?: string;\n /** Whether to create the document as a variant of the original */\n createAsVariant?: boolean;\n /** ID of the parent document when creating as a variant */\n parentDocumentId?: string;\n /** Creation mode: 'draft' creates a draft document, 'published' creates a published document */\n creationMode?: 'draft' | 'published';\n /** \n * Whether the title was found at the document's top level during extraction.\n * When false, the translated title should not be written as a top-level field.\n * This is tracked in-memory by the plugin, not sent to the translation backend.\n */\n titleFoundAtTopLevel?: boolean;\n /** \n * Whether the body/content was found at the document's top level during extraction.\n * When false, the translated body should not be written as a top-level field.\n * This is tracked in-memory by the plugin, not sent to the translation backend.\n */\n bodyFoundAtTopLevel?: boolean;\n /**\n * The field name where body content was originally found (e.g., 'body', 'content', or nested path).\n * Used to write translated content back to the correct location.\n */\n bodyFieldName?: string;\n \n // Collision Resolution Options\n /**\n * How to handle collisions when a translated document already exists.\n * - 'replace': Overwrite the existing document with new translations\n * - 'create': Create a new document (default behavior if not specified)\n */\n collisionResolutionMode?: CollisionResolutionMode;\n /**\n * How to handle the existing document when creating a new one (only for 'create' mode).\n * - 'draft': Set the existing document to draft state\n * - 'delete': Delete the existing document\n */\n existingDocumentHandling?: ExistingDocumentHandling;\n}\n\nexport interface SlugFallbackInfo {\n documentId: string;\n originalSlug: string;\n fallbackSlug: string;\n locale: string;\n reason: string;\n}\n\n/**\n * Information about a collision that was detected and resolved\n */\nexport interface CollisionResolutionInfo {\n /** Whether a collision was detected */\n collisionDetected: boolean;\n /** The resolution action that was taken */\n resolutionAction?: 'replaced' | 'created_new' | 'none';\n /** The ID of the document that was replaced, updated, or deleted */\n existingDocumentId?: string;\n /** How the existing document was handled (for 'create' mode) */\n existingDocumentAction?: 'set_to_draft' | 'deleted' | 'none';\n /** How the collision was detected */\n matchedBy?: 'parent' | 'slug-locale';\n}\n\nexport interface DocumentCreationResult {\n success: boolean;\n documentId?: string;\n document?: SanityDocument;\n error?: string;\n slugFallback?: SlugFallbackInfo;\n /** Information about collision detection and resolution */\n collisionInfo?: CollisionResolutionInfo;\n}\n\nexport interface BulkDocumentCreationResult {\n totalDocuments: number;\n successfulCreations: number;\n failedCreations: number;\n results: DocumentCreationResult[];\n errors: string[];\n rollbackInfo?: RollbackInfo;\n slugFallbacks: SlugFallbackInfo[];\n}\n\nexport interface RollbackInfo {\n canRollback: boolean;\n createdDocumentIds: string[];\n rollbackInstructions: string[];\n}\n\nexport class DocumentCreationService {\n private client: SanityClient;\n private defaultCreationMode: 'draft' | 'published' = 'draft';\n private collisionDetectionService: CollisionDetectionService | null = null;\n private defaultCollisionResolutionMode: CollisionResolutionMode = 'replace';\n private defaultExistingDocumentHandling: ExistingDocumentHandling = 'draft';\n\n constructor(client: SanityClient, defaultCreationMode?: 'draft' | 'published') {\n this.client = client;\n if (defaultCreationMode) {\n this.defaultCreationMode = defaultCreationMode;\n }\n // Initialize collision detection service\n this.collisionDetectionService = new CollisionDetectionService(client);\n }\n\n /**\n * Set the default document creation mode\n * @param mode - The creation mode to use by default ('draft' or 'published')\n */\n setDefaultCreationMode(mode: 'draft' | 'published'): void {\n this.defaultCreationMode = mode;\n }\n\n /**\n * Set the default collision resolution mode\n * @param mode - How to handle collisions ('replace' or 'create')\n */\n setDefaultCollisionResolutionMode(mode: CollisionResolutionMode): void {\n this.defaultCollisionResolutionMode = mode;\n }\n\n /**\n * Set the default existing document handling mode\n * @param handling - How to handle existing documents when creating new ('draft' or 'delete')\n */\n setDefaultExistingDocumentHandling(handling: ExistingDocumentHandling): void {\n this.defaultExistingDocumentHandling = handling;\n }\n\n /**\n * Configure collision resolution defaults\n * @param mode - Collision resolution mode\n * @param handling - Existing document handling (only applicable when mode is 'create')\n */\n setCollisionResolutionConfig(mode: CollisionResolutionMode, handling?: ExistingDocumentHandling): void {\n this.defaultCollisionResolutionMode = mode;\n if (handling) {\n this.defaultExistingDocumentHandling = handling;\n }\n }\n\n /**\n * Replace an existing document with new translated content\n * Requirements: EARS 4 - Resolution Behavior - Replace\n * \n * @param existingDocument - The document to replace\n * @param newDocument - The new translated document content\n * @param creationMode - Whether to create as draft or published\n */\n private async replaceExistingDocument(\n existingDocument: SanityDocument,\n newDocument: SanityDocument,\n creationMode: 'draft' | 'published'\n ): Promise<{ success: boolean; documentId?: string; document?: SanityDocument; error?: string }> {\n try {\n // Use the existing document's ID for the replacement\n const existingId = existingDocument._id;\n const isExistingDraft = existingId.startsWith('drafts.');\n \n // Prepare the document with the existing ID\n const documentToSave = {\n ...newDocument,\n _id: existingId,\n // Preserve system fields from existing document\n _createdAt: existingDocument._createdAt\n };\n \n // Remove fields that Sanity will manage\n delete (documentToSave as any)._rev;\n delete (documentToSave as any)._updatedAt;\n\n console.log(`[ReplaceDocument] Replacing document ${existingId}`);\n\n // Use createOrReplace to overwrite the existing document\n const replacedDocument = await this.client.createOrReplace(documentToSave);\n \n console.log(`[ReplaceDocument] Successfully replaced document ${replacedDocument._id}`);\n\n // Handle draft/published state if different from existing\n if (creationMode === 'draft' && !isExistingDraft) {\n // Existing is published but we want draft - create draft version\n const draftId = `drafts.${existingId}`;\n const draftDoc = await this.client.createOrReplace({\n ...documentToSave,\n _id: draftId\n });\n return {\n success: true,\n documentId: draftDoc._id,\n document: draftDoc\n };\n } else if (creationMode === 'published' && isExistingDraft) {\n // Existing is draft but we want published - create published version\n const publishedId = existingId.replace(/^drafts\\./, '');\n const publishedDoc = await this.client.createOrReplace({\n ...documentToSave,\n _id: publishedId\n });\n return {\n success: true,\n documentId: publishedDoc._id,\n document: publishedDoc\n };\n }\n\n return {\n success: true,\n documentId: replacedDocument._id,\n document: replacedDocument\n };\n } catch (error) {\n console.error('[ReplaceDocument] Failed to replace document:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error during document replacement'\n };\n }\n }\n\n /**\n * Handle an existing document when creating a new translation (for 'create' mode)\n * Requirements: EARS 5 - Resolution Behavior - Create\n * \n * @param existingDocument - The existing document to handle\n * @param handling - How to handle the existing document ('draft' or 'delete')\n */\n private async handleExistingDocument(\n existingDocument: SanityDocument,\n handling: ExistingDocumentHandling\n ): Promise<{ success: boolean; error?: string }> {\n try {\n const existingId = existingDocument._id;\n \n if (handling === 'delete') {\n // Delete the existing document\n console.log(`[HandleExistingDocument] Deleting document ${existingId}`);\n await this.client.delete(existingId);\n \n // Also delete draft version if exists\n if (!existingId.startsWith('drafts.')) {\n try {\n await this.client.delete(`drafts.${existingId}`);\n } catch {\n // Draft might not exist, ignore\n }\n }\n \n console.log(`[HandleExistingDocument] Successfully deleted document ${existingId}`);\n return { success: true };\n \n } else if (handling === 'draft') {\n // Set the existing document to draft state\n console.log(`[HandleExistingDocument] Setting document ${existingId} to draft state`);\n \n if (existingId.startsWith('drafts.')) {\n // Already a draft, nothing to do\n console.log(`[HandleExistingDocument] Document ${existingId} is already a draft`);\n return { success: true };\n }\n \n // For published documents, we need to create a draft and optionally unpublish\n // Create draft version\n const draftId = `drafts.${existingId}`;\n \n // Create the draft document\n await this.client.createOrReplace({\n ...existingDocument,\n _id: draftId,\n _rev: undefined, // Remove revision\n _createdAt: undefined,\n _updatedAt: undefined\n });\n \n // Delete the published version to effectively \"unpublish\"\n await this.client.delete(existingId);\n \n console.log(`[HandleExistingDocument] Successfully set document to draft: ${draftId}`);\n return { success: true };\n }\n\n return { success: true };\n } catch (error) {\n console.error('[HandleExistingDocument] Failed to handle existing document:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error during existing document handling'\n };\n }\n }\n\n /**\n * Create a new Sanity document from translation response\n * Requirements: 1.1, 1.2, 2.1, 3.2, 3.4\n */\n async createDocumentFromTranslation(\n originalDocument: SanityDocument,\n translationResponse: TranslationResponse,\n options: DocumentCreationOptions = {}\n ): Promise<DocumentCreationResult> {\n try {\n // Enhanced input validation\n const inputValidation = this.validateInputsForDocumentCreation(originalDocument, translationResponse, options);\n if (!inputValidation.isValid) {\n return {\n success: false,\n error: `Input validation failed: ${inputValidation.errors.join(', ')}`\n };\n }\n\n // Get translated content (support both new array format and legacy formats)\n const translatedContent = translationResponse.translatedDocuments?.[0] || \n translationResponse.translatedContent;\n\n // DEBUG: Log titleFoundAtTopLevel from options (tracked in-memory, not from translation response)\n console.log('[DocumentCreation] createDocumentFromTranslation:', {\n titleFoundAtTopLevelFromOptions: options.titleFoundAtTopLevel,\n translatedContentKeys: translatedContent ? Object.keys(translatedContent) : []\n });\n\n if (!translationResponse.success || !translatedContent) {\n return {\n success: false,\n error: 'Translation response does not contain valid translated content'\n };\n }\n\n // Validate translation response content\n const responseValidation = this.validateTranslationResponseForCreation(translationResponse);\n if (!responseValidation.isValid) {\n return {\n success: false,\n error: `Translation response validation failed: ${responseValidation.errors.join(', ')}`\n };\n }\n\n // Merge translated content back into original document structure\n const newDocument = await this.mergeTranslatedContent(\n originalDocument,\n translatedContent,\n options\n );\n\n // Validate the new document structure\n const validationResult = this.validateDocumentStructure(newDocument);\n if (!validationResult.isValid) {\n return {\n success: false,\n error: `Document validation failed: ${validationResult.errors.join(', ')}`\n };\n }\n\n // Additional business logic validation\n const businessValidation = this.validateBusinessRules(newDocument, originalDocument);\n if (!businessValidation.isValid) {\n return {\n success: false,\n error: `Business rule validation failed: ${businessValidation.errors.join(', ')}`\n };\n }\n\n // Handle slug fallback if needed\n let slugFallbackInfo: SlugFallbackInfo | undefined;\n if (businessValidation.slugNeedsFallback) {\n const targetLocale = options.targetLanguage || 'translated';\n const originalSlug = typeof originalDocument.slug === 'object' \n ? (originalDocument.slug as any).current \n : originalDocument.slug;\n const fallbackSlug = `${originalSlug}_${targetLocale}`;\n \n // Apply the fallback slug to the document\n if (typeof newDocument.slug === 'object' && newDocument.slug !== null && '_type' in newDocument.slug) {\n newDocument.slug = {\n _type: 'slug',\n current: fallbackSlug\n };\n } else {\n newDocument.slug = fallbackSlug;\n }\n \n slugFallbackInfo = {\n documentId: newDocument._id,\n originalSlug,\n fallbackSlug,\n locale: targetLocale,\n reason: 'Translation did not produce a different slug - locale suffix applied'\n };\n \n console.log(`[Slug Fallback Applied] Document ${newDocument._id}: \"${originalSlug}\" → \"${fallbackSlug}\"`);\n }\n\n // Determine effective creation mode (option override or default)\n const effectiveCreationMode = options.creationMode || this.defaultCreationMode;\n\n // Determine effective collision resolution settings\n const effectiveCollisionMode = options.collisionResolutionMode || this.defaultCollisionResolutionMode;\n const effectiveExistingDocHandling = options.existingDocumentHandling || this.defaultExistingDocumentHandling;\n\n // Detect collision if collision detection service is available\n let collisionResult: CollisionResult | null = null;\n let collisionInfo: CollisionResolutionInfo | undefined;\n\n if (this.collisionDetectionService && options.targetLanguage && options.parentDocumentId) {\n const translatedSlug = typeof newDocument.slug === 'object' && newDocument.slug !== null && 'current' in newDocument.slug\n ? (newDocument.slug as any).current\n : typeof newDocument.slug === 'string' ? newDocument.slug : undefined;\n\n collisionResult = await this.collisionDetectionService.detectCollision({\n sourceDocumentId: options.parentDocumentId,\n targetLocale: options.targetLanguage,\n slug: translatedSlug,\n documentType: originalDocument._type\n });\n\n if (collisionResult.detected) {\n console.log(`[CollisionHandling] Collision detected for source ${options.parentDocumentId}, locale ${options.targetLanguage}`);\n console.log(`[CollisionHandling] Resolution mode: ${effectiveCollisionMode}, Existing doc handling: ${effectiveExistingDocHandling}`);\n \n collisionInfo = {\n collisionDetected: true,\n matchedBy: collisionResult.matchedBy,\n existingDocumentId: collisionResult.existingDocument?._id\n };\n\n // Handle collision based on resolution mode\n if (effectiveCollisionMode === 'replace' && collisionResult.existingDocument) {\n // Replace mode: Overwrite the existing document\n const replaceResult = await this.replaceExistingDocument(\n collisionResult.existingDocument,\n newDocument,\n effectiveCreationMode\n );\n \n if (replaceResult.success) {\n collisionInfo.resolutionAction = 'replaced';\n collisionInfo.existingDocumentAction = 'none';\n return {\n success: true,\n documentId: replaceResult.documentId,\n document: replaceResult.document,\n slugFallback: slugFallbackInfo,\n collisionInfo\n };\n } else {\n return {\n success: false,\n error: `Failed to replace existing document: ${replaceResult.error}`,\n collisionInfo\n };\n }\n } else if (effectiveCollisionMode === 'create' && collisionResult.existingDocument) {\n // Create mode: Handle existing document, then create new\n const handleResult = await this.handleExistingDocument(\n collisionResult.existingDocument,\n effectiveExistingDocHandling\n );\n \n collisionInfo.resolutionAction = 'created_new';\n collisionInfo.existingDocumentAction = effectiveExistingDocHandling === 'draft' ? 'set_to_draft' : 'deleted';\n \n if (!handleResult.success) {\n console.warn(`[CollisionHandling] Failed to handle existing document: ${handleResult.error}`);\n // Continue with document creation even if existing doc handling fails\n }\n }\n } else {\n collisionInfo = {\n collisionDetected: false,\n resolutionAction: 'none'\n };\n }\n }\n\n // Actually create the document in Sanity\n try {\n let createdDocument: SanityDocument;\n \n if (effectiveCreationMode === 'draft') {\n // Create as draft document by prefixing ID with 'drafts.'\n const draftId = newDocument._id.startsWith('drafts.') \n ? newDocument._id \n : `drafts.${newDocument._id}`;\n \n console.log('Creating draft document in Sanity:', draftId);\n createdDocument = await this.client.create({\n ...newDocument,\n _id: draftId\n });\n console.log('Draft document created successfully:', createdDocument._id);\n } else {\n // Create as published document (no prefix)\n // Strip 'drafts.' prefix if present to ensure it's a published document\n const publishedId = newDocument._id.startsWith('drafts.') \n ? newDocument._id.replace(/^drafts\\./, '') \n : newDocument._id;\n \n console.log('Creating published document in Sanity:', publishedId);\n createdDocument = await this.client.create({\n ...newDocument,\n _id: publishedId\n });\n console.log('Published document created successfully:', createdDocument._id);\n }\n\n return {\n success: true,\n documentId: createdDocument._id,\n document: createdDocument,\n slugFallback: slugFallbackInfo,\n collisionInfo\n };\n } catch (sanityError) {\n console.error('Failed to create document in Sanity:', sanityError);\n return {\n success: false,\n error: `Failed to save document to Sanity: ${sanityError instanceof Error ? sanityError.message : 'Unknown Sanity error'}`\n };\n }\n\n } catch (error) {\n // Enhanced error handling with more context\n const errorMessage = this.formatErrorMessage(error, originalDocument._id);\n return {\n success: false,\n error: errorMessage\n };\n }\n }\n\n /**\n * Validate inputs for document creation\n * Requirements: 4.3, 4.4\n */\n private validateInputsForDocumentCreation(\n originalDocument: SanityDocument,\n translationResponse: TranslationResponse,\n options: DocumentCreationOptions\n ): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n // Validate original document\n if (!originalDocument) {\n errors.push('Original document is required');\n return { isValid: false, errors };\n }\n\n if (!originalDocument._id) {\n errors.push('Original document must have an _id');\n }\n\n if (!originalDocument._type) {\n errors.push('Original document must have a _type');\n }\n\n // Validate translation response\n if (!translationResponse) {\n errors.push('Translation response is required');\n return { isValid: false, errors };\n }\n\n // Validate options\n if (options.targetLanguage && typeof options.targetLanguage !== 'string') {\n errors.push('Target language must be a string');\n }\n\n if (options.sourceLanguage && typeof options.sourceLanguage !== 'string') {\n errors.push('Source language must be a string');\n }\n\n if (options.createAsVariant !== undefined && typeof options.createAsVariant !== 'boolean') {\n errors.push('createAsVariant must be a boolean');\n }\n\n if (options.parentDocumentId && typeof options.parentDocumentId !== 'string') {\n errors.push('parentDocumentId must be a string');\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n\n /**\n * Validate business rules for document creation\n * Requirements: 4.3, 4.4\n */\n private validateBusinessRules(\n newDocument: SanityDocument,\n originalDocument: SanityDocument\n ): { isValid: boolean; errors: string[]; slugNeedsFallback: boolean } {\n const errors: string[] = [];\n let slugNeedsFallback = false;\n\n // Ensure new document has different ID from original\n if (newDocument._id === originalDocument._id) {\n errors.push('New document ID must be different from original document ID');\n }\n\n // Ensure new document has same type as original\n if (newDocument._type !== originalDocument._type) {\n errors.push(`New document type (${newDocument._type}) must match original document type (${originalDocument._type})`);\n }\n\n // Validate that essential content exists\n const hasContent = this.documentHasContent(newDocument);\n if (!hasContent) {\n errors.push('New document must contain some translatable content');\n }\n\n // Check slug uniqueness - if same as original, mark for fallback instead of error\n if (newDocument.slug && originalDocument.slug) {\n const newSlug = typeof newDocument.slug === 'object' ? (newDocument.slug as any).current : newDocument.slug;\n const originalSlug = typeof originalDocument.slug === 'object' ? (originalDocument.slug as any).current : originalDocument.slug;\n \n if (newSlug === originalSlug) {\n // Log warning instead of failing\n console.warn(`[Slug Fallback] Document ${newDocument._id}: Slug \"${newSlug}\" is same as original. Will apply locale suffix.`);\n slugNeedsFallback = true;\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n slugNeedsFallback\n };\n }\n\n /**\n * Check if document has meaningful content\n * Searches both top-level and nested fields for title/body content\n */\n private documentHasContent(document: SanityDocument): boolean {\n const titleFields = ['title', 'name', 'heading', 'label'];\n const contentFields = ['body', 'content'];\n \n // Check for title at top level\n for (const field of titleFields) {\n if (document[field] && typeof document[field] === 'string' && document[field].trim().length > 0) {\n return true;\n }\n }\n\n // Check for body content at top level\n for (const field of contentFields) {\n if (document[field]) {\n if (typeof document[field] === 'string' && document[field].trim().length > 0) {\n return true;\n }\n if (Array.isArray(document[field]) && document[field].length > 0) {\n return true;\n }\n }\n }\n\n // Search nested fields for title or body content\n if (this.hasContentInNestedFields(document, titleFields, contentFields)) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Recursively search nested objects for title or body content\n */\n private hasContentInNestedFields(\n obj: Record<string, any>, \n titleFields: string[], \n contentFields: string[]\n ): boolean {\n for (const [key, value] of Object.entries(obj)) {\n // Skip system/internal fields\n if (key.startsWith('_')) {\n continue;\n }\n\n if (value === null || value === undefined) {\n continue;\n }\n\n // Check nested objects\n if (typeof value === 'object' && !Array.isArray(value)) {\n // Check if this nested object has a title field\n for (const titleField of titleFields) {\n if (value[titleField] && typeof value[titleField] === 'string' && value[titleField].trim().length > 0) {\n return true;\n }\n }\n\n // Check if this nested object has a body field\n for (const contentField of contentFields) {\n if (value[contentField]) {\n if (typeof value[contentField] === 'string' && value[contentField].trim().length > 0) {\n return true;\n }\n if (Array.isArray(value[contentField]) && value[contentField].length > 0) {\n return true;\n }\n }\n }\n\n // Recursively search deeper\n if (this.hasContentInNestedFields(value, titleFields, contentFields)) {\n return true;\n }\n }\n\n // Also search within arrays\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === 'object') {\n // Check if this array item has title/body fields\n for (const titleField of titleFields) {\n if (item[titleField] && typeof item[titleField] === 'string' && item[titleField].trim().length > 0) {\n return true;\n }\n }\n for (const contentField of contentFields) {\n if (item[contentField]) {\n if (typeof item[contentField] === 'string' && item[contentField].trim().length > 0) {\n return true;\n }\n if (Array.isArray(item[contentField]) && item[contentField].length > 0) {\n return true;\n }\n }\n }\n\n // Recursively search deeper\n if (this.hasContentInNestedFields(item, titleFields, contentFields)) {\n return true;\n }\n }\n }\n }\n }\n\n return false;\n }\n\n /**\n * Format error messages with additional context\n * Requirements: 4.3, 4.4\n */\n private formatErrorMessage(error: unknown, documentId?: string): string {\n const baseMessage = error instanceof Error ? error.message : 'Unknown error occurred during document creation';\n const contextInfo = documentId ? ` (Document ID: ${documentId})` : '';\n \n // Add specific error handling for common issues\n if (error instanceof Error) {\n if (error.message.includes('validation')) {\n return `Document validation error${contextInfo}: ${error.message}`;\n }\n if (error.message.includes('network') || error.message.includes('fetch')) {\n return `Network error during document creation${contextInfo}: ${error.message}`;\n }\n if (error.message.includes('permission') || error.message.includes('unauthorized')) {\n return `Permission error during document creation${contextInfo}: ${error.message}`;\n }\n }\n\n return `Document creation error${contextInfo}: ${baseMessage}`;\n }\n\n /**\n * Create multiple documents from bulk translation responses\n * Requirements: 2.1, 3.2, 3.4\n */\n async createBulkDocumentsFromTranslations(\n originalDocuments: SanityDocument[],\n translationResponses: TranslationResponse[],\n options: DocumentCreationOptions = {}\n ): Promise<BulkDocumentCreationResult> {\n const result: BulkDocumentCreationResult = {\n totalDocuments: originalDocuments.length,\n successfulCreations: 0,\n failedCreations: 0,\n results: [],\n errors: [],\n rollbackInfo: {\n canRollback: true,\n createdDocumentIds: [],\n rollbackInstructions: []\n },\n slugFallbacks: []\n };\n\n // Pre-validate all translation responses before creating any documents\n const validationErrors = this.validateBulkTranslationResponses(originalDocuments, translationResponses);\n if (validationErrors.length > 0) {\n result.errors.push(...validationErrors);\n result.failedCreations = originalDocuments.length;\n result.rollbackInfo!.canRollback = false;\n result.rollbackInfo!.rollbackInstructions.push('No documents were created due to validation failures');\n \n // Add individual failure results\n for (let i = 0; i < originalDocuments.length; i++) {\n result.results.push({\n success: false,\n error: 'Bulk validation failed - no documents created'\n });\n }\n \n return result;\n }\n\n // Track successful creations for potential rollback\n const createdDocuments: { documentId: string; originalId: string }[] = [];\n\n for (let i = 0; i < originalDocuments.length; i++) {\n const originalDocument = originalDocuments[i];\n const translationResponse = translationResponses[i];\n\n if (!translationResponse) {\n const error = `No translation response found for document ${originalDocument._id}`;\n result.results.push({\n success: false,\n error\n });\n result.errors.push(error);\n result.failedCreations++;\n continue;\n }\n\n try {\n // Additional validation before creation\n const preCreationValidation = this.validateTranslationResponseForCreation(translationResponse);\n if (!preCreationValidation.isValid) {\n const error = `Pre-creation validation failed for ${originalDocument._id}: ${preCreationValidation.errors.join(', ')}`;\n result.results.push({\n success: false,\n error\n });\n result.errors.push(error);\n result.failedCreations++;\n continue;\n }\n\n // Get all translated documents (support both new array format and legacy single document format)\n const translatedDocuments = translationResponse.translatedDocuments || \n (translationResponse.translatedContent ? [translationResponse.translatedContent] : []);\n\n if (translatedDocuments.length === 0) {\n const error = `No translated documents found in response for ${originalDocument._id}`;\n result.results.push({\n success: false,\n error\n });\n result.errors.push(error);\n result.failedCreations++;\n continue;\n }\n\n // Create a document for each translated document in the response\n for (let j = 0; j < translatedDocuments.length; j++) {\n const translatedContent = translatedDocuments[j];\n \n // Extract TARGET locale from the translated content\n // Priority: \n // 1. translatedContent.locale (document-level locale set by translation service - this IS the target)\n // 2. options.targetLanguage (from request metadata)\n // 3. fallback to 'translated'\n // NOTE: Do NOT use translatedContent.fields?.locale as that contains the \n // locale FIELD VALUE from the document, not the translation target\n const targetLocale = (\n translatedContent.locale ||\n options.targetLanguage || \n 'translated'\n );\n \n console.log(`Creating document for ${originalDocument._id} with target locale: ${targetLocale}`);\n \n // Create a single-document translation response for this document\n const singleDocumentResponse = {\n ...translationResponse,\n translatedDocuments: [translatedContent],\n translatedContent: translatedContent\n };\n\n const creationResult = await this.createDocumentFromTranslation(\n originalDocument,\n singleDocumentResponse,\n {\n ...options,\n targetLanguage: targetLocale\n }\n );\n\n result.results.push(creationResult);\n\n if (creationResult.success && creationResult.documentId) {\n result.successfulCreations++;\n createdDocuments.push({\n documentId: creationResult.documentId,\n originalId: originalDocument._id\n });\n result.rollbackInfo!.createdDocumentIds.push(creationResult.documentId);\n \n // Collect slug fallback info if applicable\n if (creationResult.slugFallback) {\n result.slugFallbacks.push(creationResult.slugFallback);\n }\n } else {\n result.failedCreations++;\n if (creationResult.error) {\n result.errors.push(creationResult.error);\n }\n }\n }\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';\n result.results.push({\n success: false,\n error: errorMessage\n });\n result.errors.push(errorMessage);\n result.failedCreations++;\n }\n }\n\n // Generate rollback instructions\n if (result.successfulCreations > 0) {\n result.rollbackInfo!.rollbackInstructions = [\n `${result.successfulCreations} documents were successfully created.`,\n 'To rollback these changes, you would need to delete the following document IDs:',\n ...result.rollbackInfo!.createdDocumentIds.map(id => `- ${id}`),\n 'Note: This plugin does not automatically delete documents for safety reasons.',\n 'Manual deletion through Sanity Studio or API calls would be required.'\n ];\n } else {\n result.rollbackInfo!.rollbackInstructions = ['No documents were created, no rollback needed.'];\n }\n\n // Log slug fallback summary if any occurred\n if (result.slugFallbacks.length > 0) {\n console.log(`[Slug Fallback Summary] ${result.slugFallbacks.length} document(s) had slug fallback applied:`);\n result.slugFallbacks.forEach(fallback => {\n console.log(` - ${fallback.documentId}: \"${fallback.originalSlug}\" → \"${fallback.fallbackSlug}\" (locale: ${fallback.locale})`);\n });\n }\n\n return result;\n }\n\n /**\n * Validate bulk translation responses before document creation\n * Requirements: 4.3, 4.4\n */\n private validateBulkTranslationResponses(\n originalDocuments: SanityDocument[],\n translationResponses: TranslationResponse[]\n ): string[] {\n const errors: string[] = [];\n\n // Check array lengths match\n if (originalDocuments.length !== translationResponses.length) {\n errors.push(`Mismatch between original documents (${originalDocuments.length}) and translation responses (${translationResponses.length})`);\n return errors; // Critical error, return immediately\n }\n\n // Validate each pair\n for (let i = 0; i < originalDocuments.length; i++) {\n const originalDoc = originalDocuments[i];\n const response = translationResponses[i];\n\n if (!originalDoc) {\n errors.push(`Original document at index ${i} is null or undefined`);\n continue;\n }\n\n if (!originalDoc._id) {\n errors.push(`Original document at index ${i} missing _id`);\n continue;\n }\n\n if (!originalDoc._type) {\n errors.push(`Original document at index ${i} missing _type`);\n continue;\n }\n\n if (!response) {\n errors.push(`Translation response at index ${i} is null or undefined`);\n continue;\n }\n\n if (!response.success) {\n // This is not necessarily an error for bulk validation, just skip this document\n continue;\n }\n\n // Check for translated content (support both new array format and legacy formats)\n const translatedDocuments = response.translatedDocuments || \n (response.translatedContent ? [response.translatedContent] : []);\n if (translatedDocuments.length === 0) {\n errors.push(`Translation response at index ${i} missing translatedDocuments/translatedContent despite success=true`);\n continue;\n }\n }\n\n return errors;\n }\n\n /**\n * Validate translation response before document creation\n * Requirements: 4.3, 4.4\n */\n private validateTranslationResponseForCreation(response: TranslationResponse): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (!response.success) {\n errors.push('Translation response indicates failure');\n return { isValid: false, errors };\n }\n\n // Get translated content (support both new array format and legacy formats)\n const translatedDocuments = response.translatedDocuments || \n (response.translatedContent ? [response.translatedContent] : []);\n \n if (translatedDocuments.length === 0) {\n errors.push('Translation response missing translatedDocuments/translatedContent');\n return { isValid: false, errors };\n }\n\n // Validate each translated document structure\n for (let i = 0; i < translatedDocuments.length; i++) {\n const content = translatedDocuments[i];\n \n if (typeof content !== 'object' || content === null) {\n errors.push(`Translated document at index ${i} must be an object`);\n continue;\n }\n\n // Check for required fields\n if (!content.body && !content.title && !content.fields) {\n errors.push(`Translated document at index ${i} must contain at least one of: body, title, or fields`);\n }\n\n // Validate body content if present\n if (content.body !== undefined) {\n if (typeof content.body !== 'string') {\n errors.push(`Translated document at index ${i} body must be a string`);\n } else if (content.body.trim().length === 0) {\n errors.push(`Translated document at index ${i} body cannot be empty`);\n }\n }\n\n // Validate title if present\n if (content.title !== undefined) {\n if (typeof content.title !== 'string') {\n errors.push(`Translated document at index ${i} title must be a string`);\n } else if (content.title.trim().length === 0) {\n errors.push(`Translated document at index ${i} title cannot be empty`);\n }\n }\n\n // Validate slug if present\n if (content.slug !== undefined) {\n if (typeof content.slug !== 'string') {\n errors.push(`Translated document at index ${i} slug must be a string`);\n } else if (content.slug.trim().length === 0) {\n errors.push(`Translated document at index ${i} slug cannot be empty`);\n } else if (!/^[a-z0-9-_]+$/.test(content.slug)) {\n errors.push(`Translated document at index ${i} slug must contain only lowercase letters, numbers, hyphens, and underscores`);\n }\n }\n\n // Validate fields if present\n if (content.fields !== undefined) {\n if (typeof content.fields !== 'object' || content.fields === null || Array.isArray(content.fields)) {\n errors.push(`Translated document at index ${i} fields must be an object`);\n }\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n\n /**\n * Create rollback plan for failed bulk operations\n * Requirements: 4.3, 4.4\n */\n createRollbackPlan(createdDocumentIds: string[]): RollbackInfo {\n if (createdDocumentIds.length === 0) {\n return {\n canRollback: true,\n createdDocumentIds: [],\n rollbackInstructions: ['No documents were created, no rollback needed.']\n };\n }\n\n return {\n canRollback: true,\n createdDocumentIds: [...createdDocumentIds],\n rollbackInstructions: [\n `Rollback plan for ${createdDocumentIds.length} created documents:`,\n '',\n '1. Manual deletion required (for safety):',\n ...createdDocumentIds.map(id => ` - Delete document: ${id}`),\n '',\n '2. Alternative: Use Sanity CLI or API:',\n ' sanity documents delete <document-id>',\n '',\n '3. Or via Sanity Client API:',\n ' client.delete(documentId)',\n '',\n 'WARNING: This plugin does not provide automatic rollback to prevent',\n 'accidental data loss. Please review each document before deletion.'\n ]\n };\n }\n\n /**\n * Parse a field path that may contain array key selectors\n * e.g., \"article.footnotes[_key == \\\"c82437b14d71\\\"].footnote\"\n * \n * @param fieldPath - The field path (may be from the field key or from the path property)\n * @returns Array of path segments with type information\n */\n private parseFieldPath(fieldPath: string): Array<{ type: 'property' | 'arrayKey'; name: string; key?: string }> {\n const segments: Array<{ type: 'property' | 'arrayKey'; name: string; key?: string }> = [];\n \n // Strip GROQ query prefix if present: *[_type == \"...\" && _id == $documentId][0].\n const groqPrefixMatch = fieldPath.match(/^\\*\\[.*?\\]\\[0\\]\\./);\n const cleanPath = groqPrefixMatch ? fieldPath.substring(groqPrefixMatch[0].length) : fieldPath;\n \n // Split by dots, but handle array key selectors like [_key == \"value\"]\n // Regex to match: propertyName or propertyName[_key == \"value\"]\n const segmentRegex = /([^.[]+)(?:\\[_key\\s*==\\s*\"([^\"]+)\"\\])?/g;\n let match;\n \n while ((match = segmentRegex.exec(cleanPath)) !== null) {\n const [, propertyName, keyValue] = match;\n \n if (keyValue) {\n // This is an array property with a key selector\n segments.push({ type: 'arrayKey', name: propertyName, key: keyValue });\n } else {\n // Regular property\n segments.push({ type: 'property', name: propertyName });\n }\n \n // Skip the dot after the match if present\n if (cleanPath[segmentRegex.lastIndex] === '.') {\n segmentRegex.lastIndex++;\n }\n }\n \n return segments;\n }\n\n /**\n * Unflatten fields with complex paths back into nested objects\n * Handles both simple dotted paths and GROQ-style array key paths:\n * - \"metadata.version\" → { metadata: { version: ... } }\n * - \"article.footnotes[_key == \\\"abc\\\"].footnote\" → { article: { footnotes: [{ _key: \"abc\", footnote: ... }] } }\n * \n * @param fields - Flattened fields with path keys\n * @param originalDocument - Original document for preserving array structure\n * @returns Unflattened nested object structure\n */\n private unflattenFields(fields: Record<string, any>, originalDocument?: any): Record<string, any> {\n const result: Record<string, any> = {};\n \n for (const [fieldKey, fieldValue] of Object.entries(fields)) {\n // Use the path property if available, otherwise use the field key\n const fieldPath = (fieldValue && typeof fieldValue === 'object' && 'path' in fieldValue) \n ? fieldValue.path \n : fieldKey;\n \n // Parse the path into segments\n const segments = this.parseFieldPath(fieldPath);\n \n if (segments.length === 0) {\n continue;\n }\n \n // Extract the actual value from TranslatableField if needed\n let actualValue = fieldValue;\n let fieldType: string | undefined;\n \n if (fieldValue && typeof fieldValue === 'object' && 'value' in fieldValue) {\n actualValue = fieldValue.value;\n fieldType = fieldValue.type;\n \n // Parse JSON strings back to objects if needed\n if (typeof actualValue === 'string') {\n // Check if it's a JSON string (arrays or objects)\n if ((actualValue.startsWith('[') && actualValue.endsWith(']')) ||\n (actualValue.startsWith('{') && actualValue.endsWith('}'))) {\n try {\n actualValue = JSON.parse(actualValue);\n } catch {\n // Keep as string if parsing fails\n }\n }\n }\n \n // Convert HTML content back to portable text for 'block' type fields\n if (fieldType === 'block' && typeof actualValue === 'string' && this.isHtmlContent(actualValue)) {\n actualValue = this.convertHtmlToPortableText(actualValue);\n }\n }\n \n // Navigate/create the nested structure\n let current = result;\n let originalCurrent = originalDocument;\n \n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i];\n const isLastSegment = i === segments.length - 1;\n \n if (segment.type === 'arrayKey') {\n // This is an array property with a key selector\n if (!(segment.name in current)) {\n // Initialize array, copying structure from original if available\n if (originalCurrent && Array.isArray(originalCurrent[segment.name])) {\n // Deep clone the original array to preserve all items and their structure\n current[segment.name] = JSON.parse(JSON.stringify(originalCurrent[segment.name]));\n } else {\n current[segment.name] = [];\n }\n }\n \n // Find or create the array item with the matching key\n const array = current[segment.name] as any[];\n let arrayItem = array.find((item: any) => item._key === segment.key);\n \n if (!arrayItem) {\n // Create a new array item with the key\n // Try to copy structure from original if available\n let originalItem: any = null;\n if (originalCurrent && Array.isArray(originalCurrent[segment.name])) {\n originalItem = originalCurrent[segment.name].find((item: any) => item._key === segment.key);\n }\n \n if (originalItem) {\n arrayItem = JSON.parse(JSON.stringify(originalItem));\n } else {\n arrayItem = { _key: segment.key };\n }\n array.push(arrayItem);\n }\n \n if (isLastSegment) {\n // This shouldn't happen - array key selectors should have a property after them\n // But handle it just in case\n Object.assign(arrayItem, actualValue);\n } else {\n current = arrayItem;\n originalCurrent = originalCurrent?.[segment.name]?.find((item: any) => item._key === segment.key);\n }\n } else {\n // Regular property\n if (isLastSegment) {\n // Set the leaf value\n current[segment.name] = actualValue;\n } else {\n // Navigate/create intermediate object\n if (!(segment.name in current)) {\n // Try to copy structure from original if available\n if (originalCurrent && typeof originalCurrent[segment.name] === 'object' && originalCurrent[segment.name] !== null) {\n current[segment.name] = Array.isArray(originalCurrent[segment.name]) \n ? JSON.parse(JSON.stringify(originalCurrent[segment.name]))\n : { ...originalCurrent[segment.name] };\n } else {\n current[segment.name] = {};\n }\n }\n current = current[segment.name];\n originalCurrent = originalCurrent?.[segment.name];\n }\n }\n }\n }\n \n return result;\n }\n\n /**\n * Get the original nested value from the original document using a dotted path\n * \n * @param document - The original document\n * @param fieldPath - The dotted path to the field\n * @returns The original value at the path, or undefined\n */\n private getOriginalValueByPath(document: SanityDocument, fieldPath: string): any {\n const pathParts = fieldPath.split('.');\n let current: any = document;\n \n for (const part of pathParts) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return undefined;\n }\n current = current[part];\n }\n \n return current;\n }\n\n /**\n * Merge translated content back into original document structure\n * Requirements: 1.2, 3.2, 3.4\n */\n private async mergeTranslatedContent(\n originalDocument: SanityDocument,\n translatedContent: {\n body: string;\n title: string;\n slug: string;\n fields: Record<string, any>;\n locale?: string;\n },\n options: DocumentCreationOptions\n ): Promise<SanityDocument> {\n // Extract the TARGET locale early for document ID generation\n // Priority: \n // 1. options.targetLanguage (explicitly passed from caller)\n // 2. translatedContent.locale (document-level locale set by translation service - this IS the target)\n // NOTE: Do NOT use translatedContent.fields?.locale as that contains the locale\n // FIELD VALUE from the document, not the translation target\n const targetLang = options.targetLanguage || translatedContent.locale;\n \n // Create a new document based on the original\n const newDocument: Partial<SanityDocument> & { _id: string; _type: string } = {\n ...originalDocument,\n _id: this.generateNewDocumentId(originalDocument._id, targetLang),\n // Remove system fields - they will be set by Sanity\n _rev: undefined,\n _createdAt: undefined,\n _updatedAt: undefined,\n };\n\n // Update title if provided AND the original had a top-level title\n // (Don't create a new top-level title field if the original only had nested title fields)\n // Use the value from options (tracked in-memory by the plugin), not from translatedContent\n const shouldWriteTopLevelTitle = options.titleFoundAtTopLevel !== false;\n \n // DEBUG: Title handling trace\n console.log('[DocumentCreation] Title handling:', {\n originalDocumentTitle: originalDocument.title,\n originalDocumentHasTitle: 'title' in originalDocument,\n translatedContentTitle: translatedContent.title,\n titleFoundAtTopLevelFromOptions: options.titleFoundAtTopLevel,\n shouldWriteTopLevelTitle,\n newDocumentTitleBefore: newDocument.title\n });\n \n if (translatedContent.title && translatedContent.title.trim() && shouldWriteTopLevelTitle) {\n newDocument.title = translatedContent.title;\n console.log('[DocumentCreation] Writing title to top level:', translatedContent.title);\n } else {\n // If we shouldn't write a top-level title, make sure we don't have one from the spread\n if (!shouldWriteTopLevelTitle && 'title' in newDocument) {\n console.log('[DocumentCreation] Removing inherited top-level title field');\n delete newDocument.title;\n } else {\n console.log('[DocumentCreation] NOT writing title. Reason:', {\n hasTitle: !!translatedContent.title,\n titleNotEmpty: translatedContent.title?.trim() ? true : false,\n shouldWriteTopLevelTitle\n });\n }\n }\n\n // Update slug if provided - ensure it's in the correct format\n if (translatedContent.slug && translatedContent.slug.trim()) {\n // Check if original document has slug as an object with _type\n if (typeof originalDocument.slug === 'object' && originalDocument.slug !== null && '_type' in originalDocument.slug) {\n newDocument.slug = {\n _type: 'slug',\n current: translatedContent.slug\n };\n } else {\n // If original was a string or didn't exist, just use the string\n newDocument.slug = translatedContent.slug;\n }\n }\n\n // Convert HTML body back to portable text and merge\n // Only write to top-level body if the original had one (tracked via options)\n const shouldWriteTopLevelBody = options.bodyFoundAtTopLevel !== false;\n \n // DEBUG: Body handling trace\n console.log('[DocumentCreation] Body handling:', {\n hasTranslatedBody: !!translatedContent.body,\n bodyFoundAtTopLevelFromOptions: options.bodyFoundAtTopLevel,\n bodyFieldNameFromOptions: options.bodyFieldName,\n shouldWriteTopLevelBody,\n originalHasBody: 'body' in originalDocument,\n originalHasContent: 'content' in originalDocument\n });\n \n if (translatedContent.body && translatedContent.body.trim()) {\n const portableTextContent = this.convertHtmlToPortableText(translatedContent.body);\n \n if (shouldWriteTopLevelBody) {\n // Find the main content field and update it\n const contentFields = ['body', 'content', 'text', 'description'];\n let fieldWritten = false;\n \n for (const field of contentFields) {\n if (originalDocument[field]) {\n newDocument[field] = portableTextContent;\n console.log('[DocumentCreation] Writing body to top-level field:', field);\n fieldWritten = true;\n break;\n }\n }\n \n // If no content field found but we should write top-level, add to body\n if (!fieldWritten) {\n newDocument.body = portableTextContent;\n console.log('[DocumentCreation] Writing body to new top-level \"body\" field');\n }\n } else {\n // Body was found in nested fields - don't write to top level\n // The translated content should be handled via the fields mechanism\n console.log('[DocumentCreation] NOT writing body to top level (was found in nested field:', options.bodyFieldName, ')');\n \n // Remove any inherited top-level body/content fields from the spread\n const contentFields = ['body', 'content', 'text', 'description'];\n for (const field of contentFields) {\n if (field in newDocument && !(field in originalDocument)) {\n console.log('[DocumentCreation] Removing inherited top-level field:', field);\n delete (newDocument as any)[field];\n }\n }\n }\n }\n\n // Merge other translated fields from the fields object\n if (translatedContent.fields && typeof translatedContent.fields === 'object') {\n // First, unflatten fields with complex paths back to nested structure\n // Pass original document to preserve array structures with keyed items\n const unflattenedFields = this.unflattenFields(translatedContent.fields, originalDocument);\n \n for (const [fieldName, fieldValue] of Object.entries(unflattenedFields)) {\n // Skip title and slug as they're handled separately above\n if (fieldName === 'title' || fieldName === 'slug' || fieldValue === undefined) {\n continue;\n }\n \n // Handle the field value based on the original document's structure\n const processedValue = this.processTranslatedField(\n fieldName,\n fieldValue,\n originalDocument[fieldName]\n );\n \n if (processedValue !== undefined) {\n newDocument[fieldName] = processedValue;\n }\n }\n \n // Also handle any fields that weren't unflattened (already at top level)\n // This handles backward compatibility with non-flattened fields\n for (const [fieldPath, fieldValue] of Object.entries(translatedContent.fields)) {\n // Skip if already processed via unflatten, or if it's title/slug\n if (fieldPath === 'title' || fieldPath === 'slug' || fieldValue === undefined) {\n continue;\n }\n \n // Only process dotted paths directly if they weren't captured by unflatten\n // (this shouldn't normally happen, but maintains backward compatibility)\n if (fieldPath.includes('.') && !(fieldPath.split('.')[0] in unflattenedFields)) {\n const originalValue = this.getOriginalValueByPath(originalDocument, fieldPath);\n const processedValue = this.processTranslatedField(\n fieldPath,\n fieldValue,\n originalValue\n );\n \n if (processedValue !== undefined) {\n // Set the value at the correct nested path\n const pathParts = fieldPath.split('.');\n let current: any = newDocument;\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i];\n if (!(part in current) || current[part] === null || typeof current[part] !== 'object') {\n current[part] = {};\n }\n current = current[part];\n }\n current[pathParts[pathParts.length - 1]] = processedValue;\n }\n }\n }\n }\n\n // Ensure locale field is ALWAYS set on translated documents with the target language\n // This is critical for collision detection to work properly\n if (targetLang) {\n // Check if original document has locale field with {dnt, value} structure\n if (originalDocument.locale && typeof originalDocument.locale === 'object' && 'value' in originalDocument.locale) {\n newDocument.locale = {\n ...(originalDocument.locale as object),\n value: targetLang\n };\n } else if (newDocument.locale && typeof newDocument.locale === 'object' && 'value' in newDocument.locale) {\n // If locale field exists in newDocument but value is empty/wrong, fix it\n newDocument.locale = {\n ...(newDocument.locale as object),\n value: targetLang\n };\n } else {\n // Always set locale as a plain string if no complex structure exists\n // This ensures all translated documents have a locale field for collision detection\n newDocument.locale = targetLang;\n }\n }\n\n // Clean up null fields that aren't defined in the original document's schema\n // Remove fields that are explicitly null or undefined to avoid schema validation errors\n const fieldsToClean = Object.keys(newDocument);\n for (const field of fieldsToClean) {\n if (newDocument[field] === null) {\n delete newDocument[field];\n }\n }\n\n // Add reference to parent document if creating as variant\n if (options.createAsVariant && options.parentDocumentId) {\n newDocument.parentDocument = {\n _type: 'reference',\n _ref: options.parentDocumentId\n };\n }\n\n return newDocument as SanityDocument;\n }\n\n /**\n * Process a translated field value and convert it to the appropriate format\n * based on the original document's structure\n */\n private processTranslatedField(\n fieldName: string,\n translatedValue: any,\n originalValue: any\n ): any {\n // If translatedValue is null or undefined, return it as-is\n if (translatedValue === null || translatedValue === undefined) {\n return translatedValue;\n }\n\n // Extract the actual value from TranslatableField objects\n let actualValue = translatedValue;\n let isDNT = false;\n \n if (translatedValue && typeof translatedValue === 'object' && 'value' in translatedValue) {\n // This is a TranslatableField object - extract the value\n actualValue = translatedValue.value;\n isDNT = translatedValue.dnt || false;\n }\n\n // If the field is marked as DNT, use the original value instead\n if (isDNT && originalValue !== undefined) {\n return originalValue;\n }\n\n // Check if the original value has a specific structure that we need to preserve\n if (originalValue && typeof originalValue === 'object' && originalValue !== null) {\n // Handle fields with {dnt, value} structure\n if ('dnt' in originalValue && 'value' in originalValue) {\n // IMPORTANT: Only use actualValue if it's not empty/null/undefined\n // If actualValue is empty but translatedValue had a nested value, try to extract it\n let finalValue = actualValue;\n \n // Handle cases where translatedValue itself has a nested value structure\n if (translatedValue && typeof translatedValue === 'object' && 'value' in translatedValue) {\n finalValue = translatedValue.value;\n }\n \n // If finalValue is still empty/null/undefined, don't replace the original\n if (finalValue === null || finalValue === undefined || finalValue === '') {\n // Check if we should keep the original value\n if (originalValue.value !== null && originalValue.value !== undefined && originalValue.value !== '') {\n return originalValue;\n }\n }\n \n return {\n dnt: isDNT,\n value: finalValue\n };\n }\n\n // Handle slug objects\n if ('_type' in originalValue && originalValue._type === 'slug') {\n return {\n _type: 'slug',\n current: typeof actualValue === 'string' ? actualValue : String(actualValue)\n };\n }\n\n // Handle date/datetime objects\n if ('_type' in originalValue && (originalValue._type === 'date' || originalValue._type === 'datetime')) {\n return {\n _type: originalValue._type,\n value: actualValue\n };\n }\n\n // Handle reference objects\n if ('_type' in originalValue && originalValue._type === 'reference') {\n return originalValue; // Keep references unchanged\n }\n }\n\n // If the actual value is an HTML string, convert it to portable text\n if (typeof actualValue === 'string' && this.isHtmlContent(actualValue)) {\n return this.convertHtmlToPortableText(actualValue);\n }\n\n // Return the actual value as-is\n return actualValue;\n }\n\n /**\n * Convert HTML content back to Sanity portable text format\n * Requirements: 3.2, 3.4\n */\n private convertHtmlToPortableText(htmlContent: string): any[] {\n // This is a simplified HTML to portable text conversion\n // In a real implementation, you might want to use a proper HTML parser\n \n if (!htmlContent || !htmlContent.trim()) {\n return [];\n }\n\n const blocks: any[] = [];\n \n // Use a more precise regex to match complete HTML tags and their content\n const htmlTagRegex = /<(h[1-6]|p|div|blockquote|li)([^>]*)>(.*?)<\\/\\1>/gi;\n let match;\n let lastIndex = 0;\n \n while ((match = htmlTagRegex.exec(htmlContent)) !== null) {\n const [, tagName, , content] = match;\n \n // Skip if content is empty or just whitespace\n if (!content.trim()) {\n continue;\n }\n \n const block = {\n _type: 'block',\n _key: this.generateBlockKey(),\n style: this.getBlockStyle(tagName.toLowerCase()),\n children: this.parseInlineContent(content),\n markDefs: []\n };\n \n // Handle list items\n if (tagName.toLowerCase() === 'li') {\n (block as any).listItem = 'bullet'; // Default to bullet, could be enhanced\n }\n \n blocks.push(block);\n lastIndex = match.index + match[0].length;\n }\n \n // Handle any remaining content that wasn't matched by tags\n const remainingContent = htmlContent.substring(lastIndex).trim();\n if (remainingContent) {\n // Remove any remaining HTML tags and create a block\n const cleanContent = remainingContent.replace(/<[^>]+>/g, '').trim();\n if (cleanContent) {\n blocks.push({\n _type: 'block',\n _key: this.generateBlockKey(),\n style: 'normal',\n children: this.parseInlineContent(cleanContent),\n markDefs: []\n });\n }\n }\n \n // If no blocks were created, create a default one with cleaned content\n if (blocks.length === 0 && htmlContent.trim()) {\n const cleanContent = htmlContent.replace(/<[^>]+>/g, '').trim();\n if (cleanContent) {\n blocks.push({\n _type: 'block',\n _key: this.generateBlockKey(),\n style: 'normal',\n children: this.parseInlineContent(cleanContent),\n markDefs: []\n });\n }\n }\n \n return blocks;\n }\n\n /**\n * Parse inline content and handle formatting\n */\n private parseInlineContent(content: string): any[] {\n const children: unknown[] = [];\n \n // Remove HTML tags and extract text with basic formatting\n const cleanContent = content\n .replace(/<strong[^>]*>(.*?)<\\/strong>/gi, '**$1**')\n .replace(/<em[^>]*>(.*?)<\\/em>/gi, '*$1*')\n .replace(/<u[^>]*>(.*?)<\\/u>/gi, '_$1_')\n .replace(/<code[^>]*>(.*?)<\\/code>/gi, '`$1`')\n .replace(/<[^>]+>/g, '') // Remove remaining HTML tags\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&amp;/g, '&')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\");\n \n if (cleanContent.trim()) {\n children.push({\n _type: 'span',\n _key: this.generateSpanKey(),\n text: cleanContent,\n marks: []\n });\n }\n \n return children;\n }\n\n /**\n * Get block style from HTML tag name\n */\n private getBlockStyle(tagName: string): string {\n const styleMap: Record<string, string> = {\n 'h1': 'h1',\n 'h2': 'h2',\n 'h3': 'h3',\n 'h4': 'h4',\n 'h5': 'h5',\n 'h6': 'h6',\n 'blockquote': 'blockquote',\n 'p': 'normal',\n 'div': 'normal',\n 'li': 'normal'\n };\n \n return styleMap[tagName] || 'normal';\n }\n\n /**\n * Check if content appears to be HTML\n */\n private isHtmlContent(content: string): boolean {\n return /<[^>]+>/.test(content);\n }\n\n /**\n * Generate a new document ID based on original ID and target language\n */\n private generateNewDocumentId(originalId: string, targetLanguage?: string): string {\n // Strip 'drafts.' prefix if present to generate clean base IDs\n const cleanId = originalId.startsWith('drafts.') \n ? originalId.replace(/^drafts\\./, '') \n : originalId;\n \n const timestamp = Date.now();\n const suffix = targetLanguage ? `-${targetLanguage}` : '-translated';\n return `${cleanId}${suffix}-${timestamp}`;\n }\n\n /**\n * Generate a unique key for portable text blocks\n */\n private generateBlockKey(): string {\n return Math.random().toString(36).substr(2, 9);\n }\n\n /**\n * Generate a unique key for spans\n */\n private generateSpanKey(): string {\n return Math.random().toString(36).substr(2, 9);\n }\n\n /**\n * Validate document structure before creation\n * Requirements: 3.4\n */\n private validateDocumentStructure(document: SanityDocument): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n // Check required fields\n if (!document._id) {\n errors.push('Document must have an _id');\n }\n\n if (!document._type) {\n errors.push('Document must have a _type');\n }\n\n // Validate portable text fields\n const portableTextFields = ['body', 'content', 'text', 'description'];\n for (const field of portableTextFields) {\n if (document[field] && Array.isArray(document[field])) {\n const validationResult = this.validatePortableTextArray(document[field], field);\n if (!validationResult.isValid) {\n errors.push(...validationResult.errors);\n }\n }\n }\n\n // Validate slug format\n if (document.slug) {\n if (typeof document.slug === 'object' && document.slug !== null && '_type' in document.slug) {\n const slugObj = document.slug as Record<string, unknown>;\n if (slugObj._type !== 'slug') {\n errors.push('Slug object must have _type of \"slug\"');\n }\n if (!slugObj.current) {\n errors.push('Slug object must have a current value');\n }\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n\n /**\n * Validate portable text array structure\n */\n private validatePortableTextArray(blocks: unknown[], fieldName: string): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (!Array.isArray(blocks)) {\n errors.push(`${fieldName} must be an array`);\n return { isValid: false, errors };\n }\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n \n if (!block || typeof block !== 'object') {\n errors.push(`${fieldName}[${i}] must be an object`);\n continue;\n }\n\n const blockObj = block as Record<string, unknown>;\n\n if (!blockObj._type) {\n errors.push(`${fieldName}[${i}] must have a _type`);\n }\n\n if (!blockObj._key) {\n errors.push(`${fieldName}[${i}] must have a _key`);\n }\n\n if (blockObj._type === 'block') {\n if (!Array.isArray(blockObj.children)) {\n errors.push(`${fieldName}[${i}] block must have children array`);\n } else {\n // Validate children\n const children = blockObj.children as unknown[];\n for (let j = 0; j < children.length; j++) {\n const child = children[j];\n if (!child || typeof child !== 'object') {\n errors.push(`${fieldName}[${i}].children[${j}] must be an object`);\n continue;\n }\n const childObj = child as Record<string, unknown>;\n if (!childObj._type) {\n errors.push(`${fieldName}[${i}].children[${j}] must have a _type`);\n }\n if (!childObj._key) {\n errors.push(`${fieldName}[${i}].children[${j}] must have a _key`);\n }\n }\n }\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n}","/**\n * Unified Configuration Storage Adapter\n * \n * Provides centralized persistence for all plugin configuration using Sanity's document storage.\n * This replaces separate OAuth and Locale storage adapters with a single unified configuration.\n * \n * Stores in a single EL_PluginConfiguration document:\n * - OAuth configuration (projectId, accessToken)\n * - Locale definitions and settings\n * - DNT field mappings by document type\n * - Auto-translate document types for Sanity Function\n */\n\nimport { SanityClient } from 'sanity';\nimport { OAuthConfig } from '../types/oauth';\nimport { LocaleConfig } from '../types/locale';\nimport { CollisionResolutionMode, ExistingDocumentHandling } from '../types/pluginConfig';\n\n/**\n * Configuration document ID for unified plugin settings\n * Internal type prefixed with EL_ to separate from customer document types\n */\nconst UNIFIED_CONFIG_DOC_ID = 'sanity-translation-plugin.config';\nconst UNIFIED_CONFIG_DOC_TYPE = 'EL_PluginConfiguration';\n\n/**\n * DNT field configuration in schema format (array)\n */\ninterface DNTFieldConfigurationSchema {\n documentType: string;\n fields: Array<{\n _key?: string;\n fieldPath: string;\n dnt: boolean;\n }>;\n}\n\n/**\n * Unified plugin configuration structure\n */\nexport interface UnifiedPluginConfig {\n /** OAuth/authentication settings */\n projectId?: string;\n accessToken?: string;\n \n /** Translation settings */\n translationApiEndpoint?: string;\n requestContentType?: 'application/json' | 'application/x-protobuf';\n responseAcceptHeader?: 'application/json' | 'application/x-protobuf';\n defaultDocumentCreationMode?: 'draft' | 'published';\n \n /** Collision resolution settings */\n collisionResolutionMode?: CollisionResolutionMode;\n existingDocumentHandling?: ExistingDocumentHandling;\n \n /** Locale configuration */\n locales?: LocaleConfig['locales'];\n defaultLocale?: string;\n \n /** DNT field map: { [documentType]: { [fieldPath]: boolean } } */\n dntFieldMap?: Record<string, Record<string, boolean>>;\n \n /** Debug mode - when enabled, shows additional DNT badges on all fields */\n debugMode?: boolean;\n \n /** Auto-translate document types - array of document type names to automatically translate on publish */\n autoTranslateDocumentTypes?: string[];\n \n /** Configuration version for migrations */\n version?: string;\n \n /** Last updated timestamp */\n lastUpdated?: string;\n}\n\n/**\n * Unified configuration storage adapter for Sanity\n */\nexport class UnifiedConfigStorage {\n private client: SanityClient;\n\n constructor(client: SanityClient) {\n this.client = client;\n }\n\n /**\n * Convert array-based DNT configuration (schema format) to map format (internal use)\n */\n private convertDNTArrayToMap(dntConfigurations?: DNTFieldConfigurationSchema[]): Record<string, Record<string, boolean>> {\n if (!dntConfigurations || !Array.isArray(dntConfigurations)) {\n return {};\n }\n\n const map: Record<string, Record<string, boolean>> = {};\n \n for (const config of dntConfigurations) {\n if (!config.documentType || !config.fields) continue;\n \n map[config.documentType] = {};\n for (const field of config.fields) {\n if (field.fieldPath) {\n map[config.documentType][field.fieldPath] = field.dnt !== false; // Default to true\n }\n }\n }\n \n return map;\n }\n\n /**\n * Convert map-based DNT configuration (internal format) to array format (schema format)\n */\n private convertDNTMapToArray(dntFieldMap?: Record<string, Record<string, boolean>>): DNTFieldConfigurationSchema[] {\n if (!dntFieldMap || typeof dntFieldMap !== 'object') {\n return [];\n }\n\n const array: DNTFieldConfigurationSchema[] = [];\n \n for (const [documentType, fields] of Object.entries(dntFieldMap)) {\n const fieldArray = Object.entries(fields).map(([fieldPath, dnt]) => ({\n _key: `${documentType}-${fieldPath}`.replace(/[^a-zA-Z0-9-_]/g, '-'),\n fieldPath,\n dnt\n }));\n \n array.push({\n documentType,\n fields: fieldArray\n });\n }\n \n return array;\n }\n\n /**\n * Load complete unified configuration from Sanity\n */\n async load(): Promise<UnifiedPluginConfig | null> {\n try {\n const doc = await this.client.fetch<any>(\n `*[_id == $id][0]`,\n { id: UNIFIED_CONFIG_DOC_ID }\n );\n\n if (!doc) {\n console.warn('No unified configuration found in Sanity');\n return null;\n }\n\n // Check for both old (dntFieldMap) and new (dntFieldConfigurations) formats\n let dntFieldMap: Record<string, Record<string, boolean>> = {};\n \n if (doc.dntFieldConfigurations) {\n // New array format - convert to map\n dntFieldMap = this.convertDNTArrayToMap(doc.dntFieldConfigurations);\n } else if (doc.dntFieldMap) {\n // Old map format - use directly (backward compatibility)\n dntFieldMap = doc.dntFieldMap;\n }\n\n // Extract config fields, excluding Sanity metadata\n const config: UnifiedPluginConfig = {\n projectId: doc.projectId,\n accessToken: doc.accessToken,\n translationApiEndpoint: doc.translationApiEndpoint,\n requestContentType: doc.requestContentType,\n responseAcceptHeader: doc.responseAcceptHeader,\n defaultDocumentCreationMode: doc.defaultDocumentCreationMode,\n collisionResolutionMode: doc.collisionResolutionMode || 'replace',\n existingDocumentHandling: doc.existingDocumentHandling || 'draft',\n locales: doc.locales || [],\n defaultLocale: doc.defaultLocale,\n dntFieldMap,\n debugMode: doc.debugMode || false,\n autoTranslateDocumentTypes: doc.autoTranslateDocumentTypes || [],\n version: doc.version || '1.0.0',\n lastUpdated: doc.lastUpdated\n };\n\n console.log('Loaded unified configuration from Sanity');\n return config;\n } catch (error) {\n console.error('Failed to load unified configuration from Sanity:', error);\n throw error;\n }\n }\n\n /**\n * Save complete unified configuration to Sanity\n */\n async save(config: UnifiedPluginConfig): Promise<void> {\n try {\n // Convert DNT map to array format for schema\n const dntFieldConfigurations = this.convertDNTMapToArray(config.dntFieldMap);\n \n const doc = {\n _id: UNIFIED_CONFIG_DOC_ID,\n _type: UNIFIED_CONFIG_DOC_TYPE,\n projectId: config.projectId,\n accessToken: config.accessToken,\n translationApiEndpoint: config.translationApiEndpoint,\n requestContentType: config.requestContentType,\n responseAcceptHeader: config.responseAcceptHeader,\n defaultDocumentCreationMode: config.defaultDocumentCreationMode,\n collisionResolutionMode: config.collisionResolutionMode,\n existingDocumentHandling: config.existingDocumentHandling,\n locales: config.locales,\n defaultLocale: config.defaultLocale,\n dntFieldConfigurations, // Store in schema format (array)\n debugMode: config.debugMode,\n autoTranslateDocumentTypes: config.autoTranslateDocumentTypes || [],\n version: config.version,\n lastUpdated: new Date().toISOString()\n };\n\n await this.client.createOrReplace(doc);\n console.log('Saved unified configuration to Sanity');\n } catch (error) {\n console.error('Failed to save unified configuration to Sanity:', error);\n throw error;\n }\n }\n\n /**\n * Update only specific fields without overwriting entire config\n */\n async update(updates: Partial<UnifiedPluginConfig>): Promise<void> {\n try {\n const current = await this.load() || {};\n const merged = {\n ...current,\n ...updates,\n lastUpdated: new Date().toISOString()\n };\n await this.save(merged);\n } catch (error) {\n console.error('Failed to update unified configuration:', error);\n throw error;\n }\n }\n\n /**\n * Delete the unified configuration document\n */\n async delete(): Promise<void> {\n try {\n await this.client.delete(UNIFIED_CONFIG_DOC_ID);\n console.log('Deleted unified configuration from Sanity');\n } catch (error) {\n console.error('Failed to delete unified configuration from Sanity:', error);\n throw error;\n }\n }\n\n // OAuth-specific methods\n \n /**\n * Load only OAuth configuration\n */\n async loadOAuth(): Promise<OAuthConfig | null> {\n const config = await this.load();\n if (!config || !config.projectId || !config.accessToken) {\n return null;\n }\n return {\n projectId: config.projectId,\n accessToken: config.accessToken\n };\n }\n\n /**\n * Save OAuth configuration\n */\n async saveOAuth(oauthConfig: OAuthConfig): Promise<void> {\n await this.update({\n projectId: oauthConfig.projectId,\n accessToken: oauthConfig.accessToken\n });\n }\n\n // Locale-specific methods\n \n /**\n * Load only locale configuration\n */\n async loadLocale(): Promise<LocaleConfig | null> {\n const config = await this.load();\n if (!config) {\n return null;\n }\n return {\n locales: config.locales || [],\n defaultLocale: config.defaultLocale,\n version: config.version || '1.0.0',\n lastUpdated: config.lastUpdated || new Date().toISOString()\n };\n }\n\n /**\n * Save locale configuration\n */\n async saveLocale(localeConfig: LocaleConfig): Promise<void> {\n await this.update({\n locales: localeConfig.locales,\n defaultLocale: localeConfig.defaultLocale\n });\n }\n\n // DNT-specific methods\n \n /**\n * Get DNT field map for a specific document type\n */\n async getDNTFieldsForType(documentType: string): Promise<Record<string, boolean>> {\n const config = await this.load();\n return config?.dntFieldMap?.[documentType] || {};\n }\n\n /**\n * Set DNT status for a field in a document type\n */\n async setDNTField(documentType: string, fieldPath: string, dnt: boolean): Promise<void> {\n const config = await this.load() || {};\n const dntFieldMap = config.dntFieldMap || {};\n \n if (!dntFieldMap[documentType]) {\n dntFieldMap[documentType] = {};\n }\n \n dntFieldMap[documentType][fieldPath] = dnt;\n \n await this.update({ dntFieldMap });\n }\n\n /**\n * Toggle DNT status for a field in a document type\n */\n async toggleDNTField(documentType: string, fieldPath: string): Promise<boolean> {\n const config = await this.load() || {};\n const dntFieldMap = config.dntFieldMap || {};\n \n if (!dntFieldMap[documentType]) {\n dntFieldMap[documentType] = {};\n }\n \n const currentValue = dntFieldMap[documentType][fieldPath] || false;\n dntFieldMap[documentType][fieldPath] = !currentValue;\n \n await this.update({ dntFieldMap });\n \n return dntFieldMap[documentType][fieldPath];\n }\n\n /**\n * Get DNT status for a specific field in a document type\n */\n async getDNTFieldStatus(documentType: string, fieldPath: string): Promise<boolean> {\n const fields = await this.getDNTFieldsForType(documentType);\n return fields[fieldPath] || false;\n }\n\n /**\n * Clear all DNT fields for a document type\n */\n async clearDNTFieldsForType(documentType: string): Promise<void> {\n const config = await this.load() || {};\n const dntFieldMap = config.dntFieldMap || {};\n \n delete dntFieldMap[documentType];\n \n await this.update({ dntFieldMap });\n }\n\n /**\n * Get all DNT field mappings\n */\n async getAllDNTFields(): Promise<Record<string, Record<string, boolean>>> {\n const config = await this.load();\n return config?.dntFieldMap || {};\n }\n\n // Translation settings methods with fallback defaults\n \n /**\n * Get translation API endpoint with fallback to default\n */\n async getTranslationEndpoint(): Promise<string> {\n const config = await this.load();\n return config?.translationApiEndpoint || 'https://app.easyling.com/_el/ext/direct/sanity';\n }\n\n /**\n * Get request content type with fallback to default\n */\n async getRequestContentType(): Promise<'application/json' | 'application/x-protobuf'> {\n const config = await this.load();\n return config?.requestContentType || 'application/json';\n }\n\n /**\n * Get response accept header with fallback to default\n */\n async getResponseAcceptHeader(): Promise<'application/json' | 'application/x-protobuf'> {\n const config = await this.load();\n return config?.responseAcceptHeader || 'application/json';\n }\n\n /**\n * Get default document creation mode with fallback to default\n */\n async getDefaultDocumentCreationMode(): Promise<'draft' | 'published'> {\n const config = await this.load();\n return config?.defaultDocumentCreationMode || 'draft';\n }\n\n /**\n * Get collision resolution mode with fallback to default ('replace')\n */\n async getCollisionResolutionMode(): Promise<CollisionResolutionMode> {\n const config = await this.load();\n return config?.collisionResolutionMode || 'replace';\n }\n\n /**\n * Get existing document handling mode with fallback to default ('draft')\n * Only applicable when collision resolution mode is 'create'\n */\n async getExistingDocumentHandling(): Promise<ExistingDocumentHandling> {\n const config = await this.load();\n return config?.existingDocumentHandling || 'draft';\n }\n\n /**\n * Get complete collision resolution configuration\n * Returns both the resolution mode and existing document handling settings\n */\n async getCollisionResolutionConfig(): Promise<{\n collisionResolutionMode: CollisionResolutionMode;\n existingDocumentHandling: ExistingDocumentHandling;\n }> {\n const config = await this.load();\n return {\n collisionResolutionMode: config?.collisionResolutionMode || 'replace',\n existingDocumentHandling: config?.existingDocumentHandling || 'draft'\n };\n }\n\n /**\n * Set collision resolution configuration\n */\n async setCollisionResolutionConfig(\n mode: CollisionResolutionMode,\n handling?: ExistingDocumentHandling\n ): Promise<void> {\n const updates: Partial<UnifiedPluginConfig> = {\n collisionResolutionMode: mode\n };\n if (handling !== undefined) {\n updates.existingDocumentHandling = handling;\n }\n await this.update(updates);\n }\n\n /**\n * Get debug mode status\n */\n async getDebugMode(): Promise<boolean> {\n const config = await this.load();\n return config?.debugMode || false;\n }\n\n /**\n * Set debug mode status\n */\n async setDebugMode(enabled: boolean): Promise<void> {\n await this.update({ debugMode: enabled });\n }\n\n // Auto-translate document types methods\n \n /**\n * Get auto-translate document types\n * Returns array of document type names that should be automatically translated on publish\n */\n async getAutoTranslateDocumentTypes(): Promise<string[]> {\n const config = await this.load();\n return config?.autoTranslateDocumentTypes || [];\n }\n\n /**\n * Set auto-translate document types\n * Sets the array of document type names that should be automatically translated on publish\n */\n async setAutoTranslateDocumentTypes(types: string[]): Promise<void> {\n await this.update({ autoTranslateDocumentTypes: types });\n }\n}\n","/**\n * HTML formatting utilities for content processing\n * Requirements: 3.3, 3.4 - Proper HTML formatting and special character escaping\n */\n\nexport interface HtmlFormattingOptions {\n preserveWhitespace?: boolean;\n escapeSpecialChars?: boolean;\n minifyOutput?: boolean;\n addLineBreaks?: boolean;\n}\n\nexport class HtmlFormatter {\n /**\n * Escape HTML special characters for JSON transmission\n * Requirement 3.4: Properly escape special characters for JSON transmission\n */\n static escapeHtml(text: string): string {\n if (typeof text !== 'string') {\n return '';\n }\n\n const htmlEscapeMap: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#x27;',\n '/': '&#x2F;',\n '`': '&#x60;'\n };\n\n return text.replace(/[&<>\"'`/]/g, (match) => htmlEscapeMap[match] || match);\n }\n\n /**\n * Unescape HTML entities back to regular characters\n */\n static unescapeHtml(html: string): string {\n if (typeof html !== 'string') {\n return '';\n }\n\n const htmlUnescapeMap: Record<string, string> = {\n '&amp;': '&',\n '&lt;': '<',\n '&gt;': '>',\n '&quot;': '\"',\n '&#x27;': \"'\",\n '&#x2F;': '/',\n '&#x60;': '`'\n };\n\n return html.replace(/&(?:amp|lt|gt|quot|#x27|#x2F|#x60);/g, (match) => htmlUnescapeMap[match] || match);\n }\n\n /**\n * Format HTML content with proper structure and indentation\n * Requirement 3.2: Preserve text structure including paragraphs, lists, and formatting\n */\n static formatHtml(html: string, options: HtmlFormattingOptions = {}): string {\n if (typeof html !== 'string') {\n return '';\n }\n\n const {\n preserveWhitespace = true,\n escapeSpecialChars = false,\n minifyOutput = false,\n addLineBreaks = true\n } = options;\n\n let formatted = html;\n\n // Escape special characters if requested\n if (escapeSpecialChars) {\n formatted = this.escapeHtml(formatted);\n }\n\n // Handle whitespace preservation\n if (!preserveWhitespace) {\n formatted = formatted.replace(/\\s+/g, ' ').trim();\n }\n\n // Add line breaks for better readability\n if (addLineBreaks && !minifyOutput) {\n formatted = formatted\n .replace(/(<\\/(?:p|div|h[1-6]|li|blockquote)>)/g, '$1\\n')\n .replace(/(<(?:p|div|h[1-6]|li|blockquote)[^>]*>)/g, '\\n$1')\n .replace(/(<br\\s*\\/?>)/g, '$1\\n')\n .replace(/\\n\\s*\\n/g, '\\n')\n .trim();\n }\n\n // Minify output if requested\n if (minifyOutput) {\n formatted = formatted\n .replace(/>\\s+</g, '><')\n .replace(/\\s+/g, ' ')\n .trim();\n }\n\n return formatted;\n }\n\n /**\n * Clean HTML content by removing unwanted tags and attributes\n */\n static cleanHtml(html: string, allowedTags: string[] = []): string {\n if (typeof html !== 'string') {\n return '';\n }\n\n const defaultAllowedTags = [\n 'p', 'div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'strong', 'em', 'u', 'code', 'pre', 'blockquote',\n 'ul', 'ol', 'li', 'a', 'img', 'figure', 'figcaption',\n 'time', 'br'\n ];\n\n const tagsToAllow = allowedTags.length > 0 ? allowedTags : defaultAllowedTags;\n const tagPattern = new RegExp(`<(?!/?(?:${tagsToAllow.join('|')})(?:\\\\s|>))[^>]+>`, 'gi');\n\n return html.replace(tagPattern, '');\n }\n\n /**\n * Wrap content in appropriate HTML structure\n * Requirement 3.3: Include HTML content in structured format\n */\n static wrapContent(content: string, wrapper: string = 'div', className?: string): string {\n if (typeof content !== 'string') {\n return '';\n }\n\n const classAttr = className ? ` class=\"${this.escapeHtml(className)}\"` : '';\n return `<${wrapper}${classAttr}>${content}</${wrapper}>`;\n }\n\n /**\n * Extract text content from HTML, removing all tags\n */\n static stripHtml(html: string): string {\n if (typeof html !== 'string') {\n return '';\n }\n\n return html\n .replace(/<[^>]*>/g, '')\n .replace(/&[^;]+;/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n }\n\n /**\n * Validate HTML structure and check for common issues\n */\n static validateHtml(html: string): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (typeof html !== 'string') {\n errors.push('HTML content must be a string');\n return { isValid: false, errors };\n }\n\n // For basic validation, we'll just check for obviously malformed tags\n // More sophisticated validation would require a proper HTML parser\n \n // Check for obviously malformed tags\n if (html.includes('<>') || html.includes('</>')) {\n errors.push('Malformed HTML tags detected');\n }\n\n // Check for unclosed angle brackets\n const openBrackets = (html.match(/</g) || []).length;\n const closeBrackets = (html.match(/>/g) || []).length;\n if (openBrackets !== closeBrackets) {\n errors.push('Mismatched angle brackets detected');\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n\n /**\n * Convert line breaks to HTML paragraphs\n */\n static lineBreaksToParagraphs(text: string): string {\n if (typeof text !== 'string') {\n return '';\n }\n\n return text\n .split(/\\n\\s*\\n/)\n .filter(paragraph => paragraph.trim())\n .map(paragraph => `<p>${this.escapeHtml(paragraph.trim())}</p>`)\n .join('\\n');\n }\n\n /**\n * Truncate HTML content while preserving structure\n */\n static truncateHtml(html: string, maxLength: number, suffix: string = '...'): string {\n if (typeof html !== 'string' || html.length <= maxLength) {\n return html;\n }\n\n const textContent = this.stripHtml(html);\n if (textContent.length <= maxLength) {\n return html;\n }\n\n // Simple truncation that tries to preserve structure\n const truncated = html.substring(0, maxLength);\n const lastCompleteTag = truncated.lastIndexOf('>');\n \n if (lastCompleteTag > 0) {\n return truncated.substring(0, lastCompleteTag + 1) + suffix;\n }\n\n return truncated + suffix;\n }\n}\n\n// Export convenience functions for backward compatibility\nexport const htmlFormatter = {\n escapeHtml: HtmlFormatter.escapeHtml,\n unescapeHtml: HtmlFormatter.unescapeHtml,\n formatHtml: HtmlFormatter.formatHtml,\n cleanHtml: HtmlFormatter.cleanHtml,\n wrapContent: HtmlFormatter.wrapContent,\n stripHtml: HtmlFormatter.stripHtml,\n validateHtml: HtmlFormatter.validateHtml,\n lineBreaksToParagraphs: HtmlFormatter.lineBreaksToParagraphs,\n truncateHtml: HtmlFormatter.truncateHtml\n};\n","/**\n * Validation functions for document and payload structure\n * Requirements: 3.4, 4.3 - Validate document structure and provide clear error messages\n */\n\nimport { DocumentContent, ExtendedDocumentContent } from '../services/contentExtractor';\nimport { TranslationRequestPayload } from '../services/translationService';\n\nexport interface ValidationResult {\n isValid: boolean;\n errors: string[];\n warnings: string[];\n}\n\nexport interface DocumentValidationOptions {\n requireTitle?: boolean;\n requireContent?: boolean;\n allowEmptyFields?: boolean;\n maxContentLength?: number;\n}\n\nexport interface PayloadValidationOptions {\n requireMetadata?: boolean;\n maxPayloadSize?: number;\n validateHtmlStructure?: boolean;\n}\n\nexport class Validator {\n /**\n * Validate Sanity document structure\n * Requirement 3.4: Validate document structure\n */\n static validateSanityDocument(\n document: any,\n options: DocumentValidationOptions = {}\n ): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const {\n requireTitle = false,\n requireContent = false,\n allowEmptyFields = true,\n maxContentLength = 1000000 // 1MB\n } = options;\n\n // Check if document exists\n if (!document) {\n errors.push('Document is null or undefined');\n return { isValid: false, errors, warnings };\n }\n\n // Check for required Sanity document fields\n if (!document._id) {\n errors.push('Document missing required _id field');\n }\n\n if (!document._type) {\n errors.push('Document missing required _type field');\n }\n\n // Validate _id format (basic Sanity ID validation)\n if (document._id && typeof document._id === 'string') {\n if (document._id.length === 0) {\n errors.push('Document _id cannot be empty');\n } else if (!/^[a-zA-Z0-9._-]+$/.test(document._id)) {\n warnings.push('Document _id contains unusual characters');\n }\n } else if (document._id) {\n errors.push('Document _id must be a string');\n }\n\n // Validate _type\n if (document._type && typeof document._type !== 'string') {\n errors.push('Document _type must be a string');\n }\n\n // Check for title if required\n if (requireTitle) {\n const titleFields = ['title', 'name', 'heading', 'label'];\n const hasTitle = titleFields.some(field => \n document[field] && typeof document[field] === 'string' && document[field].trim()\n );\n \n if (!hasTitle) {\n errors.push('Document missing required title field');\n }\n }\n\n // Check for content if required\n if (requireContent) {\n const contentFields = ['body', 'content', 'text', 'description'];\n const hasContent = contentFields.some(field => {\n const value = document[field];\n return value && (\n (typeof value === 'string' && value.trim()) ||\n (Array.isArray(value) && value.length > 0) ||\n (typeof value === 'object' && Object.keys(value).length > 0)\n );\n });\n\n if (!hasContent) {\n errors.push('Document missing required content fields');\n }\n }\n\n // Check for empty fields if not allowed\n if (!allowEmptyFields) {\n for (const [key, value] of Object.entries(document)) {\n if (!key.startsWith('_') && (value === null || value === undefined || value === '')) {\n warnings.push(`Document field '${key}' is empty`);\n }\n }\n }\n\n // Check for circular references and estimate content size\n try {\n const documentSize = JSON.stringify(document).length;\n if (documentSize > maxContentLength) {\n errors.push(`Document size (${documentSize} bytes) exceeds maximum allowed (${maxContentLength} bytes)`);\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes('circular')) {\n errors.push('Document contains circular references');\n } else {\n // Re-throw if it's not a circular reference error\n throw error;\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n };\n }\n\n /**\n * Validate document content structure\n * Requirement 3.4: Validate extracted content structure\n */\n static validateDocumentContent(content: DocumentContent): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!content) {\n errors.push('Document content is null or undefined');\n return { isValid: false, errors, warnings };\n }\n\n // Check required fields\n if (!content.documentId) {\n errors.push('Document content missing documentId');\n } else if (typeof content.documentId !== 'string') {\n errors.push('Document content documentId must be a string');\n }\n\n if (!content.title) {\n warnings.push('Document content missing title');\n } else if (typeof content.title !== 'string') {\n errors.push('Document content title must be a string');\n }\n\n if (content.htmlContent === undefined || content.htmlContent === null) {\n errors.push('Document content missing htmlContent');\n } else if (typeof content.htmlContent !== 'string') {\n errors.push('Document content htmlContent must be a string');\n } else if (content.htmlContent.trim() === '') {\n warnings.push('Document content htmlContent is empty');\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n };\n }\n\n /**\n * Validate extended document content structure\n */\n static validateExtendedDocumentContent(content: ExtendedDocumentContent): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // First validate as basic document content\n const basicValidation = this.validateDocumentContent(content);\n errors.push(...basicValidation.errors);\n warnings.push(...basicValidation.warnings);\n\n // Additional validation for extended fields\n if (content.slug !== undefined && typeof content.slug !== 'string') {\n errors.push('Extended document content slug must be a string');\n }\n\n if (content.fields !== undefined) {\n if (typeof content.fields !== 'object' || content.fields === null) {\n errors.push('Extended document content fields must be an object');\n } else if (Array.isArray(content.fields)) {\n errors.push('Extended document content fields must be an object, not an array');\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n };\n }\n\n /**\n * Validate translation request payload\n * Requirement 3.4: Validate payload structure for JSON transmission\n */\n static validateTranslationPayload(\n payload: TranslationRequestPayload,\n options: PayloadValidationOptions = {}\n ): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const {\n requireMetadata = true,\n maxPayloadSize = 10000000, // 10MB\n validateHtmlStructure = true\n } = options;\n\n if (!payload) {\n errors.push('Translation payload is null or undefined');\n return { isValid: false, errors, warnings };\n }\n\n // Validate content structure\n if (!payload.content) {\n errors.push('Translation payload missing content field');\n } else {\n if (typeof payload.content !== 'object') {\n errors.push('Translation payload content must be an object');\n } else {\n // Validate content fields\n if (!payload.content.body) {\n errors.push('Translation payload content missing body field');\n } else if (typeof payload.content.body !== 'string') {\n errors.push('Translation payload content body must be a string');\n }\n\n if (!payload.content.title) {\n warnings.push('Translation payload content missing title field');\n } else if (typeof payload.content.title !== 'string') {\n errors.push('Translation payload content title must be a string');\n }\n\n if (payload.content.slug !== undefined && typeof payload.content.slug !== 'string') {\n errors.push('Translation payload content slug must be a string');\n }\n\n if (payload.content.fields !== undefined) {\n if (typeof payload.content.fields !== 'object' || payload.content.fields === null) {\n errors.push('Translation payload content fields must be an object');\n }\n }\n }\n }\n\n // Validate format\n if (!payload.format) {\n errors.push('Translation payload missing format field');\n } else if (payload.format !== 'html') {\n errors.push('Translation payload format must be \"html\"');\n }\n\n // Validate metadata if required\n if (requireMetadata) {\n if (!payload.metadata) {\n errors.push('Translation payload missing metadata field');\n } else {\n if (typeof payload.metadata !== 'object') {\n errors.push('Translation payload metadata must be an object');\n } else {\n // Check required metadata fields\n if (!payload.metadata.documentId) {\n errors.push('Translation payload metadata missing documentId');\n }\n\n if (!payload.metadata.documentType) {\n errors.push('Translation payload metadata missing documentType');\n }\n\n if (!payload.metadata.title) {\n warnings.push('Translation payload metadata missing title');\n }\n\n // Validate optional language fields\n if (payload.metadata.sourceLanguage && typeof payload.metadata.sourceLanguage !== 'string') {\n errors.push('Translation payload metadata sourceLanguage must be a string');\n }\n\n if (payload.metadata.targetLanguage && typeof payload.metadata.targetLanguage !== 'string') {\n errors.push('Translation payload metadata targetLanguage must be a string');\n }\n }\n }\n }\n\n // Validate HTML structure if requested\n if (validateHtmlStructure && payload.content?.body) {\n const htmlValidation = this.validateHtmlContent(payload.content.body);\n if (!htmlValidation.isValid) {\n warnings.push(...htmlValidation.errors.map(error => `HTML validation: ${error}`));\n }\n }\n\n // Check payload size\n try {\n const payloadSize = JSON.stringify(payload).length;\n if (payloadSize > maxPayloadSize) {\n errors.push(`Translation payload size (${payloadSize} bytes) exceeds maximum allowed (${maxPayloadSize} bytes)`);\n }\n } catch (error) {\n errors.push('Translation payload cannot be serialized to JSON');\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n };\n }\n\n /**\n * Validate HTML content structure\n * Requirement 3.2: Validate HTML structure preservation\n */\n static validateHtmlContent(html: string): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (typeof html !== 'string') {\n errors.push('HTML content must be a string');\n return { isValid: false, errors, warnings };\n }\n\n // For basic validation, we'll just check for obviously malformed tags\n // More sophisticated validation would require a proper HTML parser\n \n // Check for obviously malformed tags\n if (html.includes('<>') || html.includes('</>')) {\n errors.push('Malformed HTML tags detected');\n }\n\n // Check for unclosed angle brackets\n const openBrackets = (html.match(/</g) || []).length;\n const closeBrackets = (html.match(/>/g) || []).length;\n if (openBrackets !== closeBrackets) {\n warnings.push('Mismatched angle brackets detected');\n }\n\n // Check for unescaped special characters in text content (basic check)\n const textContent = html.replace(/<[^>]*>/g, '');\n const unescapedChars = textContent.match(/[<>]/g);\n if (unescapedChars && unescapedChars.length > 0) {\n warnings.push('Unescaped special characters found in HTML text content');\n }\n\n // Check for empty HTML\n const strippedContent = html.replace(/<[^>]*>/g, '').trim();\n if (strippedContent === '') {\n warnings.push('HTML content appears to be empty after stripping tags');\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n };\n }\n\n /**\n * Validate array of documents for bulk operations\n * Requirement 2.1: Validate multiple documents for bulk processing\n */\n static validateDocumentArray(\n documents: any[],\n options: DocumentValidationOptions = {}\n ): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!Array.isArray(documents)) {\n errors.push('Documents must be provided as an array');\n return { isValid: false, errors, warnings };\n }\n\n if (documents.length === 0) {\n warnings.push('Document array is empty');\n return { isValid: true, errors, warnings };\n }\n\n // Validate each document\n const documentIds = new Set<string>();\n \n documents.forEach((document, index) => {\n const validation = this.validateSanityDocument(document, options);\n \n // Add index to error messages for clarity\n validation.errors.forEach(error => {\n errors.push(`Document ${index}: ${error}`);\n });\n \n validation.warnings.forEach(warning => {\n warnings.push(`Document ${index}: ${warning}`);\n });\n\n // Check for duplicate document IDs\n if (document?._id) {\n if (documentIds.has(document._id)) {\n errors.push(`Duplicate document ID found: ${document._id}`);\n } else {\n documentIds.add(document._id);\n }\n }\n });\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n };\n }\n\n /**\n * Validate endpoint URL\n */\n static validateEndpoint(endpoint: string): ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!endpoint) {\n errors.push('Endpoint URL is required');\n return { isValid: false, errors, warnings };\n }\n\n if (typeof endpoint !== 'string') {\n errors.push('Endpoint URL must be a string');\n return { isValid: false, errors, warnings };\n }\n\n // Basic URL validation\n try {\n const url = new URL(endpoint);\n \n if (!['http:', 'https:'].includes(url.protocol)) {\n errors.push('Endpoint URL must use HTTP or HTTPS protocol');\n }\n\n if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {\n warnings.push('Using localhost endpoint - ensure this is intended for development');\n }\n\n } catch (error) {\n errors.push('Invalid endpoint URL format');\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n };\n }\n}\n\n// Export convenience functions for backward compatibility\nexport const validator = {\n validateSanityDocument: Validator.validateSanityDocument,\n validateDocumentContent: Validator.validateDocumentContent,\n validateExtendedDocumentContent: Validator.validateExtendedDocumentContent,\n validateTranslationPayload: Validator.validateTranslationPayload,\n validateHtmlContent: Validator.validateHtmlContent,\n validateDocumentArray: Validator.validateDocumentArray,\n validateEndpoint: Validator.validateEndpoint\n};\n","/**\n * Plugin-specific ContentExtractor wrapper\n * \n * This file re-exports the ContentExtractor from the shared library\n * and provides a helper to create instances with DNT storage integration.\n */\n\nimport { DNTStorage } from '@easyling/sanity-connector-shared';\nimport { getDNTStorage } from './dntServiceManager';\n\n// Re-export everything from shared\nexport { \n ContentExtractor,\n type DocumentContent,\n type ExtendedDocumentContent,\n type ExtractedContent,\n type TranslatableField,\n type DNTStorage,\n type FieldContext\n} from '@easyling/sanity-connector-shared';\n\n/**\n * Create a DNT storage adapter that wraps the plugin's DNT storage\n */\nexport function createDNTStorageAdapter(): DNTStorage {\n const dntStorage = getDNTStorage();\n return {\n async getFieldsForType(documentType: string): Promise<Record<string, boolean>> {\n return dntStorage.getFieldsForType(documentType);\n }\n };\n}\n","/**\n * Collision Detection Service\n * Requirements: Translation Collision Handling - EARS 2.1, 2.2\n * \n * Detects existing translated documents for the same source document and target locale\n * to enable collision resolution handling.\n */\n\nimport { SanityClient, SanityDocument } from 'sanity';\n\n/**\n * Result of a collision detection check\n */\nexport interface CollisionResult {\n /** Whether a collision was detected */\n detected: boolean;\n /** The existing translated document if collision was detected */\n existingDocument?: SanityDocument;\n /** How the collision was identified */\n matchedBy?: 'parent' | 'slug-locale';\n}\n\n/**\n * Options for collision detection\n */\nexport interface CollisionDetectionOptions {\n /** The source document ID (the original document being translated) */\n sourceDocumentId: string;\n /** The target locale code for the translation */\n targetLocale: string;\n /** The slug of the translated document (optional, used for slug-locale matching) */\n slug?: string;\n /** The document type to search within */\n documentType?: string;\n}\n\n/**\n * Error type for collision detection operations\n */\nexport class CollisionDetectionError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: unknown\n ) {\n super(message);\n this.name = 'CollisionDetectionError';\n }\n}\n\n/**\n * Service for detecting translation collisions\n * \n * A collision occurs when a translated document already exists for the same\n * source document and target locale. The service identifies collisions using:\n * 1. Parent reference matching: parentDocument._ref == sourceDocumentId AND locale == targetLocale\n * 2. Slug-locale matching: slug.current == slug AND locale == targetLocale\n */\nexport class CollisionDetectionService {\n private client: SanityClient;\n\n constructor(client: SanityClient) {\n this.client = client;\n }\n\n /**\n * Detect if a collision exists for the given source document and target locale\n * \n * @param options - Options specifying the source document, target locale, and optional slug\n * @returns CollisionResult indicating whether a collision was found and details\n */\n async detectCollision(options: CollisionDetectionOptions): Promise<CollisionResult> {\n const { sourceDocumentId, targetLocale, slug, documentType } = options;\n\n if (!sourceDocumentId || !targetLocale) {\n throw new CollisionDetectionError(\n 'sourceDocumentId and targetLocale are required',\n 'INVALID_OPTIONS'\n );\n }\n\n // Strip drafts. prefix if present for consistent matching\n const cleanSourceId = sourceDocumentId.replace(/^drafts\\./, '');\n\n try {\n // First, check by parent reference\n const parentMatch = await this.findByParentReference(cleanSourceId, targetLocale, documentType);\n if (parentMatch) {\n console.log(`[CollisionDetection] Found collision by parent reference: ${parentMatch._id}`);\n return {\n detected: true,\n existingDocument: parentMatch,\n matchedBy: 'parent'\n };\n }\n\n // If no parent match and slug is provided, check by slug + locale\n if (slug) {\n const slugMatch = await this.findBySlugAndLocale(slug, targetLocale, documentType);\n if (slugMatch) {\n console.log(`[CollisionDetection] Found collision by slug-locale: ${slugMatch._id}`);\n return {\n detected: true,\n existingDocument: slugMatch,\n matchedBy: 'slug-locale'\n };\n }\n }\n\n // No collision found\n console.log(`[CollisionDetection] No collision detected for source ${cleanSourceId}, locale ${targetLocale}`);\n return {\n detected: false\n };\n\n } catch (error) {\n console.error('[CollisionDetection] Error during collision detection:', error);\n throw new CollisionDetectionError(\n 'Failed to detect collision',\n 'DETECTION_FAILED',\n error\n );\n }\n }\n\n /**\n * Find an existing document by parent reference and locale\n * \n * @param sourceDocumentId - The ID of the source/parent document\n * @param targetLocale - The target locale code\n * @param documentType - Optional document type to filter by\n */\n private async findByParentReference(\n sourceDocumentId: string,\n targetLocale: string,\n documentType?: string\n ): Promise<SanityDocument | null> {\n // Build query to find documents with matching parent reference and locale\n // Handle both drafts and published versions by checking both ID patterns\n // Also handle cases where locale is null but encoded in the document ID\n const typeFilter = documentType ? `&& _type == $documentType` : '';\n \n // First, try to find with explicit locale field\n const queryWithLocale = `*[\n (\n parentDocument._ref == $sourceId ||\n parentDocument._ref == $sourceIdWithDrafts\n ) &&\n (\n locale == $targetLocale ||\n locale.value == $targetLocale\n )\n ${typeFilter}\n ][0]`;\n\n // Fallback: Find by parent ref and locale pattern in document ID\n // Pattern: {sourceId}-{locale}-{timestamp} e.g., \"abc123-ja-JP-1234567890\"\n const queryWithIdPattern = `*[\n (\n parentDocument._ref == $sourceId ||\n parentDocument._ref == $sourceIdWithDrafts\n ) &&\n _id match $idPattern\n ${typeFilter}\n ][0]`;\n\n const params: Record<string, string> = {\n sourceId: sourceDocumentId,\n sourceIdWithDrafts: `drafts.${sourceDocumentId}`,\n targetLocale,\n idPattern: `*-${targetLocale}-*`\n };\n\n if (documentType) {\n params.documentType = documentType;\n }\n\n // Try with explicit locale field first\n let result = await this.client.fetch(queryWithLocale, params);\n \n // If not found, try with ID pattern matching\n if (!result) {\n result = await this.client.fetch(queryWithIdPattern, params);\n }\n \n return result || null;\n }\n\n /**\n * Find an existing document by slug and locale\n * \n * @param slug - The document slug to match\n * @param targetLocale - The target locale code\n * @param documentType - Optional document type to filter by\n */\n private async findBySlugAndLocale(\n slug: string,\n targetLocale: string,\n documentType?: string\n ): Promise<SanityDocument | null> {\n const typeFilter = documentType ? `&& _type == $documentType` : '';\n \n // Query for documents with matching slug and locale (explicit locale field)\n const queryWithLocale = `*[\n (\n slug == $slug ||\n slug.current == $slug\n ) &&\n (\n locale == $targetLocale ||\n locale.value == $targetLocale\n )\n ${typeFilter}\n ][0]`;\n\n // Fallback: Find by slug match and locale pattern in document ID\n // This handles documents where locale is null but encoded in the ID\n const queryWithIdPattern = `*[\n (\n slug == $slug ||\n slug.current == $slug\n ) &&\n _id match $idPattern\n ${typeFilter}\n ][0]`;\n\n const params: Record<string, string> = {\n slug,\n targetLocale,\n idPattern: `*-${targetLocale}-*`\n };\n\n if (documentType) {\n params.documentType = documentType;\n }\n\n // Try with explicit locale field first\n let result = await this.client.fetch(queryWithLocale, params);\n \n // If not found, try with ID pattern matching\n if (!result) {\n result = await this.client.fetch(queryWithIdPattern, params);\n }\n\n return result || null;\n }\n\n /**\n * Check if multiple collisions exist for bulk translation operations\n * \n * @param sourceDocumentId - The source document being translated\n * @param targetLocales - Array of target locale codes\n * @param slug - Optional slug for slug-locale matching\n * @param documentType - Optional document type to filter by\n * @returns Map of locale code to collision result\n */\n async detectBulkCollisions(\n sourceDocumentId: string,\n targetLocales: string[],\n slug?: string,\n documentType?: string\n ): Promise<Map<string, CollisionResult>> {\n const results = new Map<string, CollisionResult>();\n\n // Process each locale\n for (const targetLocale of targetLocales) {\n try {\n const result = await this.detectCollision({\n sourceDocumentId,\n targetLocale,\n slug,\n documentType\n });\n results.set(targetLocale, result);\n } catch (error) {\n console.error(`[CollisionDetection] Error checking locale ${targetLocale}:`, error);\n // Set as no collision detected but log the error\n results.set(targetLocale, { detected: false });\n }\n }\n\n return results;\n }\n}\n","import { SanityDocument, SanityClient } from 'sanity';\nimport { TranslationResponse } from '@easyling/sanity-connector-shared';\nimport { CollisionDetectionService, CollisionResult } from './collisionDetectionService';\nimport { CollisionResolutionMode, ExistingDocumentHandling } from '../types/pluginConfig';\n\n/**\n * Options for document creation from translation\n */\nexport interface DocumentCreationOptions {\n /** Target language code for the translated document */\n targetLanguage?: string;\n /** Source language code of the original document */\n sourceLanguage?: string;\n /** Whether to create the document as a variant of the original */\n createAsVariant?: boolean;\n /** ID of the parent document when creating as a variant */\n parentDocumentId?: string;\n /** Creation mode: 'draft' creates a draft document, 'published' creates a published document */\n creationMode?: 'draft' | 'published';\n /** \n * Whether the title was found at the document's top level during extraction.\n * When false, the translated title should not be written as a top-level field.\n * This is tracked in-memory by the plugin, not sent to the translation backend.\n */\n titleFoundAtTopLevel?: boolean;\n /** \n * Whether the body/content was found at the document's top level during extraction.\n * When false, the translated body should not be written as a top-level field.\n * This is tracked in-memory by the plugin, not sent to the translation backend.\n */\n bodyFoundAtTopLevel?: boolean;\n /**\n * The field name where body content was originally found (e.g., 'body', 'content', or nested path).\n * Used to write translated content back to the correct location.\n */\n bodyFieldName?: string;\n \n // Collision Resolution Options\n /**\n * How to handle collisions when a translated document already exists.\n * - 'replace': Overwrite the existing document with new translations\n * - 'create': Create a new document (default behavior if not specified)\n */\n collisionResolutionMode?: CollisionResolutionMode;\n /**\n * How to handle the existing document when creating a new one (only for 'create' mode).\n * - 'draft': Set the existing document to draft state\n * - 'delete': Delete the existing document\n */\n existingDocumentHandling?: ExistingDocumentHandling;\n}\n\nexport interface SlugFallbackInfo {\n documentId: string;\n originalSlug: string;\n fallbackSlug: string;\n locale: string;\n reason: string;\n}\n\n/**\n * Information about a collision that was detected and resolved\n */\nexport interface CollisionResolutionInfo {\n /** Whether a collision was detected */\n collisionDetected: boolean;\n /** The resolution action that was taken */\n resolutionAction?: 'replaced' | 'created_new' | 'none';\n /** The ID of the document that was replaced, updated, or deleted */\n existingDocumentId?: string;\n /** How the existing document was handled (for 'create' mode) */\n existingDocumentAction?: 'set_to_draft' | 'deleted' | 'none';\n /** How the collision was detected */\n matchedBy?: 'parent' | 'slug-locale';\n}\n\nexport interface DocumentCreationResult {\n success: boolean;\n documentId?: string;\n document?: SanityDocument;\n error?: string;\n slugFallback?: SlugFallbackInfo;\n /** Information about collision detection and resolution */\n collisionInfo?: CollisionResolutionInfo;\n}\n\nexport interface BulkDocumentCreationResult {\n totalDocuments: number;\n successfulCreations: number;\n failedCreations: number;\n results: DocumentCreationResult[];\n errors: string[];\n rollbackInfo?: RollbackInfo;\n slugFallbacks: SlugFallbackInfo[];\n}\n\nexport interface RollbackInfo {\n canRollback: boolean;\n createdDocumentIds: string[];\n rollbackInstructions: string[];\n}\n\nexport class DocumentCreationService {\n private client: SanityClient;\n private defaultCreationMode: 'draft' | 'published' = 'draft';\n private collisionDetectionService: CollisionDetectionService | null = null;\n private defaultCollisionResolutionMode: CollisionResolutionMode = 'replace';\n private defaultExistingDocumentHandling: ExistingDocumentHandling = 'draft';\n\n constructor(client: SanityClient, defaultCreationMode?: 'draft' | 'published') {\n this.client = client;\n if (defaultCreationMode) {\n this.defaultCreationMode = defaultCreationMode;\n }\n // Initialize collision detection service\n this.collisionDetectionService = new CollisionDetectionService(client);\n }\n\n /**\n * Set the default document creation mode\n * @param mode - The creation mode to use by default ('draft' or 'published')\n */\n setDefaultCreationMode(mode: 'draft' | 'published'): void {\n this.defaultCreationMode = mode;\n }\n\n /**\n * Set the default collision resolution mode\n * @param mode - How to handle collisions ('replace' or 'create')\n */\n setDefaultCollisionResolutionMode(mode: CollisionResolutionMode): void {\n this.defaultCollisionResolutionMode = mode;\n }\n\n /**\n * Set the default existing document handling mode\n * @param handling - How to handle existing documents when creating new ('draft' or 'delete')\n */\n setDefaultExistingDocumentHandling(handling: ExistingDocumentHandling): void {\n this.defaultExistingDocumentHandling = handling;\n }\n\n /**\n * Configure collision resolution defaults\n * @param mode - Collision resolution mode\n * @param handling - Existing document handling (only applicable when mode is 'create')\n */\n setCollisionResolutionConfig(mode: CollisionResolutionMode, handling?: ExistingDocumentHandling): void {\n this.defaultCollisionResolutionMode = mode;\n if (handling) {\n this.defaultExistingDocumentHandling = handling;\n }\n }\n\n /**\n * Replace an existing document with new translated content\n * Requirements: EARS 4 - Resolution Behavior - Replace\n * \n * @param existingDocument - The document to replace\n * @param newDocument - The new translated document content\n * @param creationMode - Whether to create as draft or published\n */\n private async replaceExistingDocument(\n existingDocument: SanityDocument,\n newDocument: SanityDocument,\n creationMode: 'draft' | 'published'\n ): Promise<{ success: boolean; documentId?: string; document?: SanityDocument; error?: string }> {\n try {\n // Use the existing document's ID for the replacement\n const existingId = existingDocument._id;\n const isExistingDraft = existingId.startsWith('drafts.');\n \n // Prepare the document with the existing ID\n const documentToSave = {\n ...newDocument,\n _id: existingId,\n // Preserve system fields from existing document\n _createdAt: existingDocument._createdAt\n };\n \n // Remove fields that Sanity will manage\n delete (documentToSave as any)._rev;\n delete (documentToSave as any)._updatedAt;\n\n console.log(`[ReplaceDocument] Replacing document ${existingId}`);\n\n // Use createOrReplace to overwrite the existing document\n const replacedDocument = await this.client.createOrReplace(documentToSave);\n \n console.log(`[ReplaceDocument] Successfully replaced document ${replacedDocument._id}`);\n\n // Handle draft/published state if different from existing\n if (creationMode === 'draft' && !isExistingDraft) {\n // Existing is published but we want draft - create draft version\n const draftId = `drafts.${existingId}`;\n const draftDoc = await this.client.createOrReplace({\n ...documentToSave,\n _id: draftId\n });\n return {\n success: true,\n documentId: draftDoc._id,\n document: draftDoc\n };\n } else if (creationMode === 'published' && isExistingDraft) {\n // Existing is draft but we want published - create published version\n const publishedId = existingId.replace(/^drafts\\./, '');\n const publishedDoc = await this.client.createOrReplace({\n ...documentToSave,\n _id: publishedId\n });\n return {\n success: true,\n documentId: publishedDoc._id,\n document: publishedDoc\n };\n }\n\n return {\n success: true,\n documentId: replacedDocument._id,\n document: replacedDocument\n };\n } catch (error) {\n console.error('[ReplaceDocument] Failed to replace document:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error during document replacement'\n };\n }\n }\n\n /**\n * Handle an existing document when creating a new translation (for 'create' mode)\n * Requirements: EARS 5 - Resolution Behavior - Create\n * \n * @param existingDocument - The existing document to handle\n * @param handling - How to handle the existing document ('draft' or 'delete')\n */\n private async handleExistingDocument(\n existingDocument: SanityDocument,\n handling: ExistingDocumentHandling\n ): Promise<{ success: boolean; error?: string }> {\n try {\n const existingId = existingDocument._id;\n \n if (handling === 'delete') {\n // Delete the existing document\n console.log(`[HandleExistingDocument] Deleting document ${existingId}`);\n await this.client.delete(existingId);\n \n // Also delete draft version if exists\n if (!existingId.startsWith('drafts.')) {\n try {\n await this.client.delete(`drafts.${existingId}`);\n } catch {\n // Draft might not exist, ignore\n }\n }\n \n console.log(`[HandleExistingDocument] Successfully deleted document ${existingId}`);\n return { success: true };\n \n } else if (handling === 'draft') {\n // Set the existing document to draft state\n console.log(`[HandleExistingDocument] Setting document ${existingId} to draft state`);\n \n if (existingId.startsWith('drafts.')) {\n // Already a draft, nothing to do\n console.log(`[HandleExistingDocument] Document ${existingId} is already a draft`);\n return { success: true };\n }\n \n // For published documents, we need to create a draft and optionally unpublish\n // Create draft version\n const draftId = `drafts.${existingId}`;\n \n // Create the draft document\n await this.client.createOrReplace({\n ...existingDocument,\n _id: draftId,\n _rev: undefined, // Remove revision\n _createdAt: undefined,\n _updatedAt: undefined\n });\n \n // Delete the published version to effectively \"unpublish\"\n await this.client.delete(existingId);\n \n console.log(`[HandleExistingDocument] Successfully set document to draft: ${draftId}`);\n return { success: true };\n }\n\n return { success: true };\n } catch (error) {\n console.error('[HandleExistingDocument] Failed to handle existing document:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error during existing document handling'\n };\n }\n }\n\n /**\n * Create a new Sanity document from translation response\n * Requirements: 1.1, 1.2, 2.1, 3.2, 3.4\n */\n async createDocumentFromTranslation(\n originalDocument: SanityDocument,\n translationResponse: TranslationResponse,\n options: DocumentCreationOptions = {}\n ): Promise<DocumentCreationResult> {\n try {\n // Enhanced input validation\n const inputValidation = this.validateInputsForDocumentCreation(originalDocument, translationResponse, options);\n if (!inputValidation.isValid) {\n return {\n success: false,\n error: `Input validation failed: ${inputValidation.errors.join(', ')}`\n };\n }\n\n // Get translated content (support both new array format and legacy formats)\n const translatedContent = translationResponse.translatedDocuments?.[0] || \n translationResponse.translatedContent;\n\n // DEBUG: Log titleFoundAtTopLevel from options (tracked in-memory, not from translation response)\n console.log('[DocumentCreation] createDocumentFromTranslation:', {\n titleFoundAtTopLevelFromOptions: options.titleFoundAtTopLevel,\n translatedContentKeys: translatedContent ? Object.keys(translatedContent) : []\n });\n\n if (!translationResponse.success || !translatedContent) {\n return {\n success: false,\n error: 'Translation response does not contain valid translated content'\n };\n }\n\n // Validate translation response content\n const responseValidation = this.validateTranslationResponseForCreation(translationResponse);\n if (!responseValidation.isValid) {\n return {\n success: false,\n error: `Translation response validation failed: ${responseValidation.errors.join(', ')}`\n };\n }\n\n // Merge translated content back into original document structure\n const newDocument = await this.mergeTranslatedContent(\n originalDocument,\n translatedContent,\n options\n );\n\n // Validate the new document structure\n const validationResult = this.validateDocumentStructure(newDocument);\n if (!validationResult.isValid) {\n return {\n success: false,\n error: `Document validation failed: ${validationResult.errors.join(', ')}`\n };\n }\n\n // Additional business logic validation\n const businessValidation = this.validateBusinessRules(newDocument, originalDocument);\n if (!businessValidation.isValid) {\n return {\n success: false,\n error: `Business rule validation failed: ${businessValidation.errors.join(', ')}`\n };\n }\n\n // Handle slug fallback if needed\n let slugFallbackInfo: SlugFallbackInfo | undefined;\n if (businessValidation.slugNeedsFallback) {\n const targetLocale = options.targetLanguage || 'translated';\n const originalSlug = typeof originalDocument.slug === 'object' \n ? (originalDocument.slug as any).current \n : originalDocument.slug;\n const fallbackSlug = `${originalSlug}_${targetLocale}`;\n \n // Apply the fallback slug to the document\n if (typeof newDocument.slug === 'object' && newDocument.slug !== null && '_type' in newDocument.slug) {\n newDocument.slug = {\n _type: 'slug',\n current: fallbackSlug\n };\n } else {\n newDocument.slug = fallbackSlug;\n }\n \n slugFallbackInfo = {\n documentId: newDocument._id,\n originalSlug,\n fallbackSlug,\n locale: targetLocale,\n reason: 'Translation did not produce a different slug - locale suffix applied'\n };\n \n console.log(`[Slug Fallback Applied] Document ${newDocument._id}: \"${originalSlug}\" → \"${fallbackSlug}\"`);\n }\n\n // Determine effective creation mode (option override or default)\n const effectiveCreationMode = options.creationMode || this.defaultCreationMode;\n\n // Determine effective collision resolution settings\n const effectiveCollisionMode = options.collisionResolutionMode || this.defaultCollisionResolutionMode;\n const effectiveExistingDocHandling = options.existingDocumentHandling || this.defaultExistingDocumentHandling;\n\n // Detect collision if collision detection service is available\n let collisionResult: CollisionResult | null = null;\n let collisionInfo: CollisionResolutionInfo | undefined;\n\n if (this.collisionDetectionService && options.targetLanguage && options.parentDocumentId) {\n const translatedSlug = typeof newDocument.slug === 'object' && newDocument.slug !== null && 'current' in newDocument.slug\n ? (newDocument.slug as any).current\n : typeof newDocument.slug === 'string' ? newDocument.slug : undefined;\n\n collisionResult = await this.collisionDetectionService.detectCollision({\n sourceDocumentId: options.parentDocumentId,\n targetLocale: options.targetLanguage,\n slug: translatedSlug,\n documentType: originalDocument._type\n });\n\n if (collisionResult.detected) {\n console.log(`[CollisionHandling] Collision detected for source ${options.parentDocumentId}, locale ${options.targetLanguage}`);\n console.log(`[CollisionHandling] Resolution mode: ${effectiveCollisionMode}, Existing doc handling: ${effectiveExistingDocHandling}`);\n \n collisionInfo = {\n collisionDetected: true,\n matchedBy: collisionResult.matchedBy,\n existingDocumentId: collisionResult.existingDocument?._id\n };\n\n // Handle collision based on resolution mode\n if (effectiveCollisionMode === 'replace' && collisionResult.existingDocument) {\n // Replace mode: Overwrite the existing document\n const replaceResult = await this.replaceExistingDocument(\n collisionResult.existingDocument,\n newDocument,\n effectiveCreationMode\n );\n \n if (replaceResult.success) {\n collisionInfo.resolutionAction = 'replaced';\n collisionInfo.existingDocumentAction = 'none';\n return {\n success: true,\n documentId: replaceResult.documentId,\n document: replaceResult.document,\n slugFallback: slugFallbackInfo,\n collisionInfo\n };\n } else {\n return {\n success: false,\n error: `Failed to replace existing document: ${replaceResult.error}`,\n collisionInfo\n };\n }\n } else if (effectiveCollisionMode === 'create' && collisionResult.existingDocument) {\n // Create mode: Handle existing document, then create new\n const handleResult = await this.handleExistingDocument(\n collisionResult.existingDocument,\n effectiveExistingDocHandling\n );\n \n collisionInfo.resolutionAction = 'created_new';\n collisionInfo.existingDocumentAction = effectiveExistingDocHandling === 'draft' ? 'set_to_draft' : 'deleted';\n \n if (!handleResult.success) {\n console.warn(`[CollisionHandling] Failed to handle existing document: ${handleResult.error}`);\n // Continue with document creation even if existing doc handling fails\n }\n }\n } else {\n collisionInfo = {\n collisionDetected: false,\n resolutionAction: 'none'\n };\n }\n }\n\n // Actually create the document in Sanity\n try {\n let createdDocument: SanityDocument;\n \n if (effectiveCreationMode === 'draft') {\n // Create as draft document by prefixing ID with 'drafts.'\n const draftId = newDocument._id.startsWith('drafts.') \n ? newDocument._id \n : `drafts.${newDocument._id}`;\n \n console.log('Creating draft document in Sanity:', draftId);\n createdDocument = await this.client.create({\n ...newDocument,\n _id: draftId\n });\n console.log('Draft document created successfully:', createdDocument._id);\n } else {\n // Create as published document (no prefix)\n // Strip 'drafts.' prefix if present to ensure it's a published document\n const publishedId = newDocument._id.startsWith('drafts.') \n ? newDocument._id.replace(/^drafts\\./, '') \n : newDocument._id;\n \n console.log('Creating published document in Sanity:', publishedId);\n createdDocument = await this.client.create({\n ...newDocument,\n _id: publishedId\n });\n console.log('Published document created successfully:', createdDocument._id);\n }\n\n return {\n success: true,\n documentId: createdDocument._id,\n document: createdDocument,\n slugFallback: slugFallbackInfo,\n collisionInfo\n };\n } catch (sanityError) {\n console.error('Failed to create document in Sanity:', sanityError);\n return {\n success: false,\n error: `Failed to save document to Sanity: ${sanityError instanceof Error ? sanityError.message : 'Unknown Sanity error'}`\n };\n }\n\n } catch (error) {\n // Enhanced error handling with more context\n const errorMessage = this.formatErrorMessage(error, originalDocument._id);\n return {\n success: false,\n error: errorMessage\n };\n }\n }\n\n /**\n * Validate inputs for document creation\n * Requirements: 4.3, 4.4\n */\n private validateInputsForDocumentCreation(\n originalDocument: SanityDocument,\n translationResponse: TranslationResponse,\n options: DocumentCreationOptions\n ): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n // Validate original document\n if (!originalDocument) {\n errors.push('Original document is required');\n return { isValid: false, errors };\n }\n\n if (!originalDocument._id) {\n errors.push('Original document must have an _id');\n }\n\n if (!originalDocument._type) {\n errors.push('Original document must have a _type');\n }\n\n // Validate translation response\n if (!translationResponse) {\n errors.push('Translation response is required');\n return { isValid: false, errors };\n }\n\n // Validate options\n if (options.targetLanguage && typeof options.targetLanguage !== 'string') {\n errors.push('Target language must be a string');\n }\n\n if (options.sourceLanguage && typeof options.sourceLanguage !== 'string') {\n errors.push('Source language must be a string');\n }\n\n if (options.createAsVariant !== undefined && typeof options.createAsVariant !== 'boolean') {\n errors.push('createAsVariant must be a boolean');\n }\n\n if (options.parentDocumentId && typeof options.parentDocumentId !== 'string') {\n errors.push('parentDocumentId must be a string');\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n\n /**\n * Validate business rules for document creation\n * Requirements: 4.3, 4.4\n */\n private validateBusinessRules(\n newDocument: SanityDocument,\n originalDocument: SanityDocument\n ): { isValid: boolean; errors: string[]; slugNeedsFallback: boolean } {\n const errors: string[] = [];\n let slugNeedsFallback = false;\n\n // Ensure new document has different ID from original\n if (newDocument._id === originalDocument._id) {\n errors.push('New document ID must be different from original document ID');\n }\n\n // Ensure new document has same type as original\n if (newDocument._type !== originalDocument._type) {\n errors.push(`New document type (${newDocument._type}) must match original document type (${originalDocument._type})`);\n }\n\n // Validate that essential content exists\n const hasContent = this.documentHasContent(newDocument);\n if (!hasContent) {\n errors.push('New document must contain some translatable content');\n }\n\n // Check slug uniqueness - if same as original, mark for fallback instead of error\n if (newDocument.slug && originalDocument.slug) {\n const newSlug = typeof newDocument.slug === 'object' ? (newDocument.slug as any).current : newDocument.slug;\n const originalSlug = typeof originalDocument.slug === 'object' ? (originalDocument.slug as any).current : originalDocument.slug;\n \n if (newSlug === originalSlug) {\n // Log warning instead of failing\n console.warn(`[Slug Fallback] Document ${newDocument._id}: Slug \"${newSlug}\" is same as original. Will apply locale suffix.`);\n slugNeedsFallback = true;\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n slugNeedsFallback\n };\n }\n\n /**\n * Check if document has meaningful content\n * Searches both top-level and nested fields for title/body content\n */\n private documentHasContent(document: SanityDocument): boolean {\n const titleFields = ['title', 'name', 'heading', 'label'];\n const contentFields = ['body', 'content'];\n \n // Check for title at top level\n for (const field of titleFields) {\n if (document[field] && typeof document[field] === 'string' && document[field].trim().length > 0) {\n return true;\n }\n }\n\n // Check for body content at top level\n for (const field of contentFields) {\n if (document[field]) {\n if (typeof document[field] === 'string' && document[field].trim().length > 0) {\n return true;\n }\n if (Array.isArray(document[field]) && document[field].length > 0) {\n return true;\n }\n }\n }\n\n // Search nested fields for title or body content\n if (this.hasContentInNestedFields(document, titleFields, contentFields)) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Recursively search nested objects for title or body content\n */\n private hasContentInNestedFields(\n obj: Record<string, any>, \n titleFields: string[], \n contentFields: string[]\n ): boolean {\n for (const [key, value] of Object.entries(obj)) {\n // Skip system/internal fields\n if (key.startsWith('_')) {\n continue;\n }\n\n if (value === null || value === undefined) {\n continue;\n }\n\n // Check nested objects\n if (typeof value === 'object' && !Array.isArray(value)) {\n // Check if this nested object has a title field\n for (const titleField of titleFields) {\n if (value[titleField] && typeof value[titleField] === 'string' && value[titleField].trim().length > 0) {\n return true;\n }\n }\n\n // Check if this nested object has a body field\n for (const contentField of contentFields) {\n if (value[contentField]) {\n if (typeof value[contentField] === 'string' && value[contentField].trim().length > 0) {\n return true;\n }\n if (Array.isArray(value[contentField]) && value[contentField].length > 0) {\n return true;\n }\n }\n }\n\n // Recursively search deeper\n if (this.hasContentInNestedFields(value, titleFields, contentFields)) {\n return true;\n }\n }\n\n // Also search within arrays\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === 'object') {\n // Check if this array item has title/body fields\n for (const titleField of titleFields) {\n if (item[titleField] && typeof item[titleField] === 'string' && item[titleField].trim().length > 0) {\n return true;\n }\n }\n for (const contentField of contentFields) {\n if (item[contentField]) {\n if (typeof item[contentField] === 'string' && item[contentField].trim().length > 0) {\n return true;\n }\n if (Array.isArray(item[contentField]) && item[contentField].length > 0) {\n return true;\n }\n }\n }\n\n // Recursively search deeper\n if (this.hasContentInNestedFields(item, titleFields, contentFields)) {\n return true;\n }\n }\n }\n }\n }\n\n return false;\n }\n\n /**\n * Format error messages with additional context\n * Requirements: 4.3, 4.4\n */\n private formatErrorMessage(error: unknown, documentId?: string): string {\n const baseMessage = error instanceof Error ? error.message : 'Unknown error occurred during document creation';\n const contextInfo = documentId ? ` (Document ID: ${documentId})` : '';\n \n // Add specific error handling for common issues\n if (error instanceof Error) {\n if (error.message.includes('validation')) {\n return `Document validation error${contextInfo}: ${error.message}`;\n }\n if (error.message.includes('network') || error.message.includes('fetch')) {\n return `Network error during document creation${contextInfo}: ${error.message}`;\n }\n if (error.message.includes('permission') || error.message.includes('unauthorized')) {\n return `Permission error during document creation${contextInfo}: ${error.message}`;\n }\n }\n\n return `Document creation error${contextInfo}: ${baseMessage}`;\n }\n\n /**\n * Create multiple documents from bulk translation responses\n * Requirements: 2.1, 3.2, 3.4\n */\n async createBulkDocumentsFromTranslations(\n originalDocuments: SanityDocument[],\n translationResponses: TranslationResponse[],\n options: DocumentCreationOptions = {}\n ): Promise<BulkDocumentCreationResult> {\n const result: BulkDocumentCreationResult = {\n totalDocuments: originalDocuments.length,\n successfulCreations: 0,\n failedCreations: 0,\n results: [],\n errors: [],\n rollbackInfo: {\n canRollback: true,\n createdDocumentIds: [],\n rollbackInstructions: []\n },\n slugFallbacks: []\n };\n\n // Pre-validate all translation responses before creating any documents\n const validationErrors = this.validateBulkTranslationResponses(originalDocuments, translationResponses);\n if (validationErrors.length > 0) {\n result.errors.push(...validationErrors);\n result.failedCreations = originalDocuments.length;\n result.rollbackInfo!.canRollback = false;\n result.rollbackInfo!.rollbackInstructions.push('No documents were created due to validation failures');\n \n // Add individual failure results\n for (let i = 0; i < originalDocuments.length; i++) {\n result.results.push({\n success: false,\n error: 'Bulk validation failed - no documents created'\n });\n }\n \n return result;\n }\n\n // Track successful creations for potential rollback\n const createdDocuments: { documentId: string; originalId: string }[] = [];\n\n for (let i = 0; i < originalDocuments.length; i++) {\n const originalDocument = originalDocuments[i];\n const translationResponse = translationResponses[i];\n\n if (!translationResponse) {\n const error = `No translation response found for document ${originalDocument._id}`;\n result.results.push({\n success: false,\n error\n });\n result.errors.push(error);\n result.failedCreations++;\n continue;\n }\n\n try {\n // Additional validation before creation\n const preCreationValidation = this.validateTranslationResponseForCreation(translationResponse);\n if (!preCreationValidation.isValid) {\n const error = `Pre-creation validation failed for ${originalDocument._id}: ${preCreationValidation.errors.join(', ')}`;\n result.results.push({\n success: false,\n error\n });\n result.errors.push(error);\n result.failedCreations++;\n continue;\n }\n\n // Get all translated documents (support both new array format and legacy single document format)\n const translatedDocuments = translationResponse.translatedDocuments || \n (translationResponse.translatedContent ? [translationResponse.translatedContent] : []);\n\n if (translatedDocuments.length === 0) {\n const error = `No translated documents found in response for ${originalDocument._id}`;\n result.results.push({\n success: false,\n error\n });\n result.errors.push(error);\n result.failedCreations++;\n continue;\n }\n\n // Create a document for each translated document in the response\n for (let j = 0; j < translatedDocuments.length; j++) {\n const translatedContent = translatedDocuments[j];\n \n // Extract TARGET locale from the translated content\n // Priority: \n // 1. translatedContent.locale (document-level locale set by translation service - this IS the target)\n // 2. options.targetLanguage (from request metadata)\n // 3. fallback to 'translated'\n // NOTE: Do NOT use translatedContent.fields?.locale as that contains the \n // locale FIELD VALUE from the document, not the translation target\n const targetLocale = (\n translatedContent.locale ||\n options.targetLanguage || \n 'translated'\n );\n \n console.log(`Creating document for ${originalDocument._id} with target locale: ${targetLocale}`);\n \n // Create a single-document translation response for this document\n const singleDocumentResponse = {\n ...translationResponse,\n translatedDocuments: [translatedContent],\n translatedContent: translatedContent\n };\n\n const creationResult = await this.createDocumentFromTranslation(\n originalDocument,\n singleDocumentResponse,\n {\n ...options,\n targetLanguage: targetLocale\n }\n );\n\n result.results.push(creationResult);\n\n if (creationResult.success && creationResult.documentId) {\n result.successfulCreations++;\n createdDocuments.push({\n documentId: creationResult.documentId,\n originalId: originalDocument._id\n });\n result.rollbackInfo!.createdDocumentIds.push(creationResult.documentId);\n \n // Collect slug fallback info if applicable\n if (creationResult.slugFallback) {\n result.slugFallbacks.push(creationResult.slugFallback);\n }\n } else {\n result.failedCreations++;\n if (creationResult.error) {\n result.errors.push(creationResult.error);\n }\n }\n }\n\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';\n result.results.push({\n success: false,\n error: errorMessage\n });\n result.errors.push(errorMessage);\n result.failedCreations++;\n }\n }\n\n // Generate rollback instructions\n if (result.successfulCreations > 0) {\n result.rollbackInfo!.rollbackInstructions = [\n `${result.successfulCreations} documents were successfully created.`,\n 'To rollback these changes, you would need to delete the following document IDs:',\n ...result.rollbackInfo!.createdDocumentIds.map(id => `- ${id}`),\n 'Note: This plugin does not automatically delete documents for safety reasons.',\n 'Manual deletion through Sanity Studio or API calls would be required.'\n ];\n } else {\n result.rollbackInfo!.rollbackInstructions = ['No documents were created, no rollback needed.'];\n }\n\n // Log slug fallback summary if any occurred\n if (result.slugFallbacks.length > 0) {\n console.log(`[Slug Fallback Summary] ${result.slugFallbacks.length} document(s) had slug fallback applied:`);\n result.slugFallbacks.forEach(fallback => {\n console.log(` - ${fallback.documentId}: \"${fallback.originalSlug}\" → \"${fallback.fallbackSlug}\" (locale: ${fallback.locale})`);\n });\n }\n\n return result;\n }\n\n /**\n * Validate bulk translation responses before document creation\n * Requirements: 4.3, 4.4\n */\n private validateBulkTranslationResponses(\n originalDocuments: SanityDocument[],\n translationResponses: TranslationResponse[]\n ): string[] {\n const errors: string[] = [];\n\n // Check array lengths match\n if (originalDocuments.length !== translationResponses.length) {\n errors.push(`Mismatch between original documents (${originalDocuments.length}) and translation responses (${translationResponses.length})`);\n return errors; // Critical error, return immediately\n }\n\n // Validate each pair\n for (let i = 0; i < originalDocuments.length; i++) {\n const originalDoc = originalDocuments[i];\n const response = translationResponses[i];\n\n if (!originalDoc) {\n errors.push(`Original document at index ${i} is null or undefined`);\n continue;\n }\n\n if (!originalDoc._id) {\n errors.push(`Original document at index ${i} missing _id`);\n continue;\n }\n\n if (!originalDoc._type) {\n errors.push(`Original document at index ${i} missing _type`);\n continue;\n }\n\n if (!response) {\n errors.push(`Translation response at index ${i} is null or undefined`);\n continue;\n }\n\n if (!response.success) {\n // This is not necessarily an error for bulk validation, just skip this document\n continue;\n }\n\n // Check for translated content (support both new array format and legacy formats)\n const translatedDocuments = response.translatedDocuments || \n (response.translatedContent ? [response.translatedContent] : []);\n if (translatedDocuments.length === 0) {\n errors.push(`Translation response at index ${i} missing translatedDocuments/translatedContent despite success=true`);\n continue;\n }\n }\n\n return errors;\n }\n\n /**\n * Validate translation response before document creation\n * Requirements: 4.3, 4.4\n */\n private validateTranslationResponseForCreation(response: TranslationResponse): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (!response.success) {\n errors.push('Translation response indicates failure');\n return { isValid: false, errors };\n }\n\n // Get translated content (support both new array format and legacy formats)\n const translatedDocuments = response.translatedDocuments || \n (response.translatedContent ? [response.translatedContent] : []);\n \n if (translatedDocuments.length === 0) {\n errors.push('Translation response missing translatedDocuments/translatedContent');\n return { isValid: false, errors };\n }\n\n // Validate each translated document structure\n for (let i = 0; i < translatedDocuments.length; i++) {\n const content = translatedDocuments[i];\n \n if (typeof content !== 'object' || content === null) {\n errors.push(`Translated document at index ${i} must be an object`);\n continue;\n }\n\n // Check for required fields\n if (!content.body && !content.title && !content.fields) {\n errors.push(`Translated document at index ${i} must contain at least one of: body, title, or fields`);\n }\n\n // Validate body content if present\n if (content.body !== undefined) {\n if (typeof content.body !== 'string') {\n errors.push(`Translated document at index ${i} body must be a string`);\n } else if (content.body.trim().length === 0) {\n errors.push(`Translated document at index ${i} body cannot be empty`);\n }\n }\n\n // Validate title if present\n if (content.title !== undefined) {\n if (typeof content.title !== 'string') {\n errors.push(`Translated document at index ${i} title must be a string`);\n } else if (content.title.trim().length === 0) {\n errors.push(`Translated document at index ${i} title cannot be empty`);\n }\n }\n\n // Validate slug if present\n if (content.slug !== undefined) {\n if (typeof content.slug !== 'string') {\n errors.push(`Translated document at index ${i} slug must be a string`);\n } else if (content.slug.trim().length === 0) {\n errors.push(`Translated document at index ${i} slug cannot be empty`);\n } else if (!/^[a-z0-9-_]+$/.test(content.slug)) {\n errors.push(`Translated document at index ${i} slug must contain only lowercase letters, numbers, hyphens, and underscores`);\n }\n }\n\n // Validate fields if present\n if (content.fields !== undefined) {\n if (typeof content.fields !== 'object' || content.fields === null || Array.isArray(content.fields)) {\n errors.push(`Translated document at index ${i} fields must be an object`);\n }\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n\n /**\n * Create rollback plan for failed bulk operations\n * Requirements: 4.3, 4.4\n */\n createRollbackPlan(createdDocumentIds: string[]): RollbackInfo {\n if (createdDocumentIds.length === 0) {\n return {\n canRollback: true,\n createdDocumentIds: [],\n rollbackInstructions: ['No documents were created, no rollback needed.']\n };\n }\n\n return {\n canRollback: true,\n createdDocumentIds: [...createdDocumentIds],\n rollbackInstructions: [\n `Rollback plan for ${createdDocumentIds.length} created documents:`,\n '',\n '1. Manual deletion required (for safety):',\n ...createdDocumentIds.map(id => ` - Delete document: ${id}`),\n '',\n '2. Alternative: Use Sanity CLI or API:',\n ' sanity documents delete <document-id>',\n '',\n '3. Or via Sanity Client API:',\n ' client.delete(documentId)',\n '',\n 'WARNING: This plugin does not provide automatic rollback to prevent',\n 'accidental data loss. Please review each document before deletion.'\n ]\n };\n }\n\n /**\n * Parse a field path that may contain array key selectors\n * e.g., \"article.footnotes[_key == \\\"c82437b14d71\\\"].footnote\"\n * \n * @param fieldPath - The field path (may be from the field key or from the path property)\n * @returns Array of path segments with type information\n */\n private parseFieldPath(fieldPath: string): Array<{ type: 'property' | 'arrayKey'; name: string; key?: string }> {\n const segments: Array<{ type: 'property' | 'arrayKey'; name: string; key?: string }> = [];\n \n // Strip GROQ query prefix if present: *[_type == \"...\" && _id == $documentId][0].\n const groqPrefixMatch = fieldPath.match(/^\\*\\[.*?\\]\\[0\\]\\./);\n const cleanPath = groqPrefixMatch ? fieldPath.substring(groqPrefixMatch[0].length) : fieldPath;\n \n // Split by dots, but handle array key selectors like [_key == \"value\"]\n // Regex to match: propertyName or propertyName[_key == \"value\"]\n const segmentRegex = /([^.[]+)(?:\\[_key\\s*==\\s*\"([^\"]+)\"\\])?/g;\n let match;\n \n while ((match = segmentRegex.exec(cleanPath)) !== null) {\n const [, propertyName, keyValue] = match;\n \n if (keyValue) {\n // This is an array property with a key selector\n segments.push({ type: 'arrayKey', name: propertyName, key: keyValue });\n } else {\n // Regular property\n segments.push({ type: 'property', name: propertyName });\n }\n \n // Skip the dot after the match if present\n if (cleanPath[segmentRegex.lastIndex] === '.') {\n segmentRegex.lastIndex++;\n }\n }\n \n return segments;\n }\n\n /**\n * Unflatten fields with complex paths back into nested objects\n * Handles both simple dotted paths and GROQ-style array key paths:\n * - \"metadata.version\" → { metadata: { version: ... } }\n * - \"article.footnotes[_key == \\\"abc\\\"].footnote\" → { article: { footnotes: [{ _key: \"abc\", footnote: ... }] } }\n * \n * @param fields - Flattened fields with path keys\n * @param originalDocument - Original document for preserving array structure\n * @returns Unflattened nested object structure\n */\n private unflattenFields(fields: Record<string, any>, originalDocument?: any): Record<string, any> {\n const result: Record<string, any> = {};\n \n for (const [fieldKey, fieldValue] of Object.entries(fields)) {\n // Use the path property if available, otherwise use the field key\n const fieldPath = (fieldValue && typeof fieldValue === 'object' && 'path' in fieldValue) \n ? fieldValue.path \n : fieldKey;\n \n // Parse the path into segments\n const segments = this.parseFieldPath(fieldPath);\n \n if (segments.length === 0) {\n continue;\n }\n \n // Extract the actual value from TranslatableField if needed\n let actualValue = fieldValue;\n let fieldType: string | undefined;\n \n if (fieldValue && typeof fieldValue === 'object' && 'value' in fieldValue) {\n actualValue = fieldValue.value;\n fieldType = fieldValue.type;\n \n // Parse JSON strings back to objects if needed\n if (typeof actualValue === 'string') {\n // Check if it's a JSON string (arrays or objects)\n if ((actualValue.startsWith('[') && actualValue.endsWith(']')) ||\n (actualValue.startsWith('{') && actualValue.endsWith('}'))) {\n try {\n actualValue = JSON.parse(actualValue);\n } catch {\n // Keep as string if parsing fails\n }\n }\n }\n \n // Convert HTML content back to portable text for 'block' type fields\n if (fieldType === 'block' && typeof actualValue === 'string' && this.isHtmlContent(actualValue)) {\n actualValue = this.convertHtmlToPortableText(actualValue);\n }\n }\n \n // Navigate/create the nested structure\n let current = result;\n let originalCurrent = originalDocument;\n \n for (let i = 0; i < segments.length; i++) {\n const segment = segments[i];\n const isLastSegment = i === segments.length - 1;\n \n if (segment.type === 'arrayKey') {\n // This is an array property with a key selector\n if (!(segment.name in current)) {\n // Initialize array, copying structure from original if available\n if (originalCurrent && Array.isArray(originalCurrent[segment.name])) {\n // Deep clone the original array to preserve all items and their structure\n current[segment.name] = JSON.parse(JSON.stringify(originalCurrent[segment.name]));\n } else {\n current[segment.name] = [];\n }\n }\n \n // Find or create the array item with the matching key\n const array = current[segment.name] as any[];\n let arrayItem = array.find((item: any) => item._key === segment.key);\n \n if (!arrayItem) {\n // Create a new array item with the key\n // Try to copy structure from original if available\n let originalItem: any = null;\n if (originalCurrent && Array.isArray(originalCurrent[segment.name])) {\n originalItem = originalCurrent[segment.name].find((item: any) => item._key === segment.key);\n }\n \n if (originalItem) {\n arrayItem = JSON.parse(JSON.stringify(originalItem));\n } else {\n arrayItem = { _key: segment.key };\n }\n array.push(arrayItem);\n }\n \n if (isLastSegment) {\n // This shouldn't happen - array key selectors should have a property after them\n // But handle it just in case\n Object.assign(arrayItem, actualValue);\n } else {\n current = arrayItem;\n originalCurrent = originalCurrent?.[segment.name]?.find((item: any) => item._key === segment.key);\n }\n } else {\n // Regular property\n if (isLastSegment) {\n // Set the leaf value\n current[segment.name] = actualValue;\n } else {\n // Navigate/create intermediate object\n if (!(segment.name in current)) {\n // Try to copy structure from original if available\n if (originalCurrent && typeof originalCurrent[segment.name] === 'object' && originalCurrent[segment.name] !== null) {\n current[segment.name] = Array.isArray(originalCurrent[segment.name]) \n ? JSON.parse(JSON.stringify(originalCurrent[segment.name]))\n : { ...originalCurrent[segment.name] };\n } else {\n current[segment.name] = {};\n }\n }\n current = current[segment.name];\n originalCurrent = originalCurrent?.[segment.name];\n }\n }\n }\n }\n \n return result;\n }\n\n /**\n * Get the original nested value from the original document using a dotted path\n * \n * @param document - The original document\n * @param fieldPath - The dotted path to the field\n * @returns The original value at the path, or undefined\n */\n private getOriginalValueByPath(document: SanityDocument, fieldPath: string): any {\n const pathParts = fieldPath.split('.');\n let current: any = document;\n \n for (const part of pathParts) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return undefined;\n }\n current = current[part];\n }\n \n return current;\n }\n\n /**\n * Merge translated content back into original document structure\n * Requirements: 1.2, 3.2, 3.4\n */\n private async mergeTranslatedContent(\n originalDocument: SanityDocument,\n translatedContent: {\n body: string;\n title: string;\n slug: string;\n fields: Record<string, any>;\n locale?: string;\n },\n options: DocumentCreationOptions\n ): Promise<SanityDocument> {\n // Extract the TARGET locale early for document ID generation\n // Priority: \n // 1. options.targetLanguage (explicitly passed from caller)\n // 2. translatedContent.locale (document-level locale set by translation service - this IS the target)\n // NOTE: Do NOT use translatedContent.fields?.locale as that contains the locale\n // FIELD VALUE from the document, not the translation target\n const targetLang = options.targetLanguage || translatedContent.locale;\n \n // Create a new document based on the original\n const newDocument: Partial<SanityDocument> & { _id: string; _type: string } = {\n ...originalDocument,\n _id: this.generateNewDocumentId(originalDocument._id, targetLang),\n // Remove system fields - they will be set by Sanity\n _rev: undefined,\n _createdAt: undefined,\n _updatedAt: undefined,\n };\n\n // Update title if provided AND the original had a top-level title\n // (Don't create a new top-level title field if the original only had nested title fields)\n // Use the value from options (tracked in-memory by the plugin), not from translatedContent\n const shouldWriteTopLevelTitle = options.titleFoundAtTopLevel !== false;\n \n // DEBUG: Title handling trace\n console.log('[DocumentCreation] Title handling:', {\n originalDocumentTitle: originalDocument.title,\n originalDocumentHasTitle: 'title' in originalDocument,\n translatedContentTitle: translatedContent.title,\n titleFoundAtTopLevelFromOptions: options.titleFoundAtTopLevel,\n shouldWriteTopLevelTitle,\n newDocumentTitleBefore: newDocument.title\n });\n \n if (translatedContent.title && translatedContent.title.trim() && shouldWriteTopLevelTitle) {\n newDocument.title = translatedContent.title;\n console.log('[DocumentCreation] Writing title to top level:', translatedContent.title);\n } else {\n // If we shouldn't write a top-level title, make sure we don't have one from the spread\n if (!shouldWriteTopLevelTitle && 'title' in newDocument) {\n console.log('[DocumentCreation] Removing inherited top-level title field');\n delete newDocument.title;\n } else {\n console.log('[DocumentCreation] NOT writing title. Reason:', {\n hasTitle: !!translatedContent.title,\n titleNotEmpty: translatedContent.title?.trim() ? true : false,\n shouldWriteTopLevelTitle\n });\n }\n }\n\n // Update slug if provided - ensure it's in the correct format\n if (translatedContent.slug && translatedContent.slug.trim()) {\n // Check if original document has slug as an object with _type\n if (typeof originalDocument.slug === 'object' && originalDocument.slug !== null && '_type' in originalDocument.slug) {\n newDocument.slug = {\n _type: 'slug',\n current: translatedContent.slug\n };\n } else {\n // If original was a string or didn't exist, just use the string\n newDocument.slug = translatedContent.slug;\n }\n }\n\n // Convert HTML body back to portable text and merge\n // Only write to top-level body if the original had one (tracked via options)\n const shouldWriteTopLevelBody = options.bodyFoundAtTopLevel !== false;\n \n // DEBUG: Body handling trace\n console.log('[DocumentCreation] Body handling:', {\n hasTranslatedBody: !!translatedContent.body,\n bodyFoundAtTopLevelFromOptions: options.bodyFoundAtTopLevel,\n bodyFieldNameFromOptions: options.bodyFieldName,\n shouldWriteTopLevelBody,\n originalHasBody: 'body' in originalDocument,\n originalHasContent: 'content' in originalDocument\n });\n \n if (translatedContent.body && translatedContent.body.trim()) {\n const portableTextContent = this.convertHtmlToPortableText(translatedContent.body);\n \n if (shouldWriteTopLevelBody) {\n // Find the main content field and update it\n const contentFields = ['body', 'content', 'text', 'description'];\n let fieldWritten = false;\n \n for (const field of contentFields) {\n if (originalDocument[field]) {\n newDocument[field] = portableTextContent;\n console.log('[DocumentCreation] Writing body to top-level field:', field);\n fieldWritten = true;\n break;\n }\n }\n \n // If no content field found but we should write top-level, add to body\n if (!fieldWritten) {\n newDocument.body = portableTextContent;\n console.log('[DocumentCreation] Writing body to new top-level \"body\" field');\n }\n } else {\n // Body was found in nested fields - don't write to top level\n // The translated content should be handled via the fields mechanism\n console.log('[DocumentCreation] NOT writing body to top level (was found in nested field:', options.bodyFieldName, ')');\n \n // Remove any inherited top-level body/content fields from the spread\n const contentFields = ['body', 'content', 'text', 'description'];\n for (const field of contentFields) {\n if (field in newDocument && !(field in originalDocument)) {\n console.log('[DocumentCreation] Removing inherited top-level field:', field);\n delete (newDocument as any)[field];\n }\n }\n }\n }\n\n // Merge other translated fields from the fields object\n if (translatedContent.fields && typeof translatedContent.fields === 'object') {\n // First, unflatten fields with complex paths back to nested structure\n // Pass original document to preserve array structures with keyed items\n const unflattenedFields = this.unflattenFields(translatedContent.fields, originalDocument);\n \n for (const [fieldName, fieldValue] of Object.entries(unflattenedFields)) {\n // Skip title and slug as they're handled separately above\n if (fieldName === 'title' || fieldName === 'slug' || fieldValue === undefined) {\n continue;\n }\n \n // Handle the field value based on the original document's structure\n const processedValue = this.processTranslatedField(\n fieldName,\n fieldValue,\n originalDocument[fieldName]\n );\n \n if (processedValue !== undefined) {\n newDocument[fieldName] = processedValue;\n }\n }\n \n // Also handle any fields that weren't unflattened (already at top level)\n // This handles backward compatibility with non-flattened fields\n for (const [fieldPath, fieldValue] of Object.entries(translatedContent.fields)) {\n // Skip if already processed via unflatten, or if it's title/slug\n if (fieldPath === 'title' || fieldPath === 'slug' || fieldValue === undefined) {\n continue;\n }\n \n // Only process dotted paths directly if they weren't captured by unflatten\n // (this shouldn't normally happen, but maintains backward compatibility)\n if (fieldPath.includes('.') && !(fieldPath.split('.')[0] in unflattenedFields)) {\n const originalValue = this.getOriginalValueByPath(originalDocument, fieldPath);\n const processedValue = this.processTranslatedField(\n fieldPath,\n fieldValue,\n originalValue\n );\n \n if (processedValue !== undefined) {\n // Set the value at the correct nested path\n const pathParts = fieldPath.split('.');\n let current: any = newDocument;\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i];\n if (!(part in current) || current[part] === null || typeof current[part] !== 'object') {\n current[part] = {};\n }\n current = current[part];\n }\n current[pathParts[pathParts.length - 1]] = processedValue;\n }\n }\n }\n }\n\n // Ensure locale field is ALWAYS set on translated documents with the target language\n // This is critical for collision detection to work properly\n if (targetLang) {\n // Check if original document has locale field with {dnt, value} structure\n if (originalDocument.locale && typeof originalDocument.locale === 'object' && 'value' in originalDocument.locale) {\n newDocument.locale = {\n ...(originalDocument.locale as object),\n value: targetLang\n };\n } else if (newDocument.locale && typeof newDocument.locale === 'object' && 'value' in newDocument.locale) {\n // If locale field exists in newDocument but value is empty/wrong, fix it\n newDocument.locale = {\n ...(newDocument.locale as object),\n value: targetLang\n };\n } else {\n // Always set locale as a plain string if no complex structure exists\n // This ensures all translated documents have a locale field for collision detection\n newDocument.locale = targetLang;\n }\n }\n\n // Clean up null fields that aren't defined in the original document's schema\n // Remove fields that are explicitly null or undefined to avoid schema validation errors\n const fieldsToClean = Object.keys(newDocument);\n for (const field of fieldsToClean) {\n if (newDocument[field] === null) {\n delete newDocument[field];\n }\n }\n\n // Add reference to parent document if creating as variant\n if (options.createAsVariant && options.parentDocumentId) {\n newDocument.parentDocument = {\n _type: 'reference',\n _ref: options.parentDocumentId\n };\n }\n\n return newDocument as SanityDocument;\n }\n\n /**\n * Process a translated field value and convert it to the appropriate format\n * based on the original document's structure\n */\n private processTranslatedField(\n fieldName: string,\n translatedValue: any,\n originalValue: any\n ): any {\n // If translatedValue is null or undefined, return it as-is\n if (translatedValue === null || translatedValue === undefined) {\n return translatedValue;\n }\n\n // Extract the actual value from TranslatableField objects\n let actualValue = translatedValue;\n let isDNT = false;\n \n if (translatedValue && typeof translatedValue === 'object' && 'value' in translatedValue) {\n // This is a TranslatableField object - extract the value\n actualValue = translatedValue.value;\n isDNT = translatedValue.dnt || false;\n }\n\n // If the field is marked as DNT, use the original value instead\n if (isDNT && originalValue !== undefined) {\n return originalValue;\n }\n\n // Check if the original value has a specific structure that we need to preserve\n if (originalValue && typeof originalValue === 'object' && originalValue !== null) {\n // Handle fields with {dnt, value} structure\n if ('dnt' in originalValue && 'value' in originalValue) {\n // IMPORTANT: Only use actualValue if it's not empty/null/undefined\n // If actualValue is empty but translatedValue had a nested value, try to extract it\n let finalValue = actualValue;\n \n // Handle cases where translatedValue itself has a nested value structure\n if (translatedValue && typeof translatedValue === 'object' && 'value' in translatedValue) {\n finalValue = translatedValue.value;\n }\n \n // If finalValue is still empty/null/undefined, don't replace the original\n if (finalValue === null || finalValue === undefined || finalValue === '') {\n // Check if we should keep the original value\n if (originalValue.value !== null && originalValue.value !== undefined && originalValue.value !== '') {\n return originalValue;\n }\n }\n \n return {\n dnt: isDNT,\n value: finalValue\n };\n }\n\n // Handle slug objects\n if ('_type' in originalValue && originalValue._type === 'slug') {\n return {\n _type: 'slug',\n current: typeof actualValue === 'string' ? actualValue : String(actualValue)\n };\n }\n\n // Handle date/datetime objects\n if ('_type' in originalValue && (originalValue._type === 'date' || originalValue._type === 'datetime')) {\n return {\n _type: originalValue._type,\n value: actualValue\n };\n }\n\n // Handle reference objects\n if ('_type' in originalValue && originalValue._type === 'reference') {\n return originalValue; // Keep references unchanged\n }\n }\n\n // If the actual value is an HTML string, convert it to portable text\n if (typeof actualValue === 'string' && this.isHtmlContent(actualValue)) {\n return this.convertHtmlToPortableText(actualValue);\n }\n\n // Return the actual value as-is\n return actualValue;\n }\n\n /**\n * Convert HTML content back to Sanity portable text format\n * Requirements: 3.2, 3.4\n */\n private convertHtmlToPortableText(htmlContent: string): any[] {\n // This is a simplified HTML to portable text conversion\n // In a real implementation, you might want to use a proper HTML parser\n \n if (!htmlContent || !htmlContent.trim()) {\n return [];\n }\n\n const blocks: any[] = [];\n \n // Use a more precise regex to match complete HTML tags and their content\n const htmlTagRegex = /<(h[1-6]|p|div|blockquote|li)([^>]*)>(.*?)<\\/\\1>/gi;\n let match;\n let lastIndex = 0;\n \n while ((match = htmlTagRegex.exec(htmlContent)) !== null) {\n const [, tagName, , content] = match;\n \n // Skip if content is empty or just whitespace\n if (!content.trim()) {\n continue;\n }\n \n const block = {\n _type: 'block',\n _key: this.generateBlockKey(),\n style: this.getBlockStyle(tagName.toLowerCase()),\n children: this.parseInlineContent(content),\n markDefs: []\n };\n \n // Handle list items\n if (tagName.toLowerCase() === 'li') {\n (block as any).listItem = 'bullet'; // Default to bullet, could be enhanced\n }\n \n blocks.push(block);\n lastIndex = match.index + match[0].length;\n }\n \n // Handle any remaining content that wasn't matched by tags\n const remainingContent = htmlContent.substring(lastIndex).trim();\n if (remainingContent) {\n // Remove any remaining HTML tags and create a block\n const cleanContent = remainingContent.replace(/<[^>]+>/g, '').trim();\n if (cleanContent) {\n blocks.push({\n _type: 'block',\n _key: this.generateBlockKey(),\n style: 'normal',\n children: this.parseInlineContent(cleanContent),\n markDefs: []\n });\n }\n }\n \n // If no blocks were created, create a default one with cleaned content\n if (blocks.length === 0 && htmlContent.trim()) {\n const cleanContent = htmlContent.replace(/<[^>]+>/g, '').trim();\n if (cleanContent) {\n blocks.push({\n _type: 'block',\n _key: this.generateBlockKey(),\n style: 'normal',\n children: this.parseInlineContent(cleanContent),\n markDefs: []\n });\n }\n }\n \n return blocks;\n }\n\n /**\n * Parse inline content and handle formatting\n */\n private parseInlineContent(content: string): any[] {\n const children: unknown[] = [];\n \n // Remove HTML tags and extract text with basic formatting\n const cleanContent = content\n .replace(/<strong[^>]*>(.*?)<\\/strong>/gi, '**$1**')\n .replace(/<em[^>]*>(.*?)<\\/em>/gi, '*$1*')\n .replace(/<u[^>]*>(.*?)<\\/u>/gi, '_$1_')\n .replace(/<code[^>]*>(.*?)<\\/code>/gi, '`$1`')\n .replace(/<[^>]+>/g, '') // Remove remaining HTML tags\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&amp;/g, '&')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\");\n \n if (cleanContent.trim()) {\n children.push({\n _type: 'span',\n _key: this.generateSpanKey(),\n text: cleanContent,\n marks: []\n });\n }\n \n return children;\n }\n\n /**\n * Get block style from HTML tag name\n */\n private getBlockStyle(tagName: string): string {\n const styleMap: Record<string, string> = {\n 'h1': 'h1',\n 'h2': 'h2',\n 'h3': 'h3',\n 'h4': 'h4',\n 'h5': 'h5',\n 'h6': 'h6',\n 'blockquote': 'blockquote',\n 'p': 'normal',\n 'div': 'normal',\n 'li': 'normal'\n };\n \n return styleMap[tagName] || 'normal';\n }\n\n /**\n * Check if content appears to be HTML\n */\n private isHtmlContent(content: string): boolean {\n return /<[^>]+>/.test(content);\n }\n\n /**\n * Generate a new document ID based on original ID and target language\n */\n private generateNewDocumentId(originalId: string, targetLanguage?: string): string {\n // Strip 'drafts.' prefix if present to generate clean base IDs\n const cleanId = originalId.startsWith('drafts.') \n ? originalId.replace(/^drafts\\./, '') \n : originalId;\n \n const timestamp = Date.now();\n const suffix = targetLanguage ? `-${targetLanguage}` : '-translated';\n return `${cleanId}${suffix}-${timestamp}`;\n }\n\n /**\n * Generate a unique key for portable text blocks\n */\n private generateBlockKey(): string {\n return Math.random().toString(36).substr(2, 9);\n }\n\n /**\n * Generate a unique key for spans\n */\n private generateSpanKey(): string {\n return Math.random().toString(36).substr(2, 9);\n }\n\n /**\n * Validate document structure before creation\n * Requirements: 3.4\n */\n private validateDocumentStructure(document: SanityDocument): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n // Check required fields\n if (!document._id) {\n errors.push('Document must have an _id');\n }\n\n if (!document._type) {\n errors.push('Document must have a _type');\n }\n\n // Validate portable text fields\n const portableTextFields = ['body', 'content', 'text', 'description'];\n for (const field of portableTextFields) {\n if (document[field] && Array.isArray(document[field])) {\n const validationResult = this.validatePortableTextArray(document[field], field);\n if (!validationResult.isValid) {\n errors.push(...validationResult.errors);\n }\n }\n }\n\n // Validate slug format\n if (document.slug) {\n if (typeof document.slug === 'object' && document.slug !== null && '_type' in document.slug) {\n const slugObj = document.slug as Record<string, unknown>;\n if (slugObj._type !== 'slug') {\n errors.push('Slug object must have _type of \"slug\"');\n }\n if (!slugObj.current) {\n errors.push('Slug object must have a current value');\n }\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n\n /**\n * Validate portable text array structure\n */\n private validatePortableTextArray(blocks: unknown[], fieldName: string): { isValid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n if (!Array.isArray(blocks)) {\n errors.push(`${fieldName} must be an array`);\n return { isValid: false, errors };\n }\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n \n if (!block || typeof block !== 'object') {\n errors.push(`${fieldName}[${i}] must be an object`);\n continue;\n }\n\n const blockObj = block as Record<string, unknown>;\n\n if (!blockObj._type) {\n errors.push(`${fieldName}[${i}] must have a _type`);\n }\n\n if (!blockObj._key) {\n errors.push(`${fieldName}[${i}] must have a _key`);\n }\n\n if (blockObj._type === 'block') {\n if (!Array.isArray(blockObj.children)) {\n errors.push(`${fieldName}[${i}] block must have children array`);\n } else {\n // Validate children\n const children = blockObj.children as unknown[];\n for (let j = 0; j < children.length; j++) {\n const child = children[j];\n if (!child || typeof child !== 'object') {\n errors.push(`${fieldName}[${i}].children[${j}] must be an object`);\n continue;\n }\n const childObj = child as Record<string, unknown>;\n if (!childObj._type) {\n errors.push(`${fieldName}[${i}].children[${j}] must have a _type`);\n }\n if (!childObj._key) {\n errors.push(`${fieldName}[${i}].children[${j}] must have a _key`);\n }\n }\n }\n }\n }\n\n return {\n isValid: errors.length === 0,\n errors\n };\n }\n}","/**\n * Locale configuration type definitions\n * Requirements: 5.1, 5.2, 5.3\n */\n\n/**\n * Individual locale definition with metadata\n */\nexport interface LocaleDefinition {\n /** Locale code in ISO 639-1 + ISO 3166-1 format (e.g., \"en-US\", \"fr-FR\") */\n code: string;\n /** Human-readable display name (e.g., \"English (United States)\") */\n displayName: string;\n /** Whether this locale is enabled for translation */\n enabled: boolean;\n /** Timestamp when this locale was created */\n createdAt: string;\n /** Timestamp when this locale was last updated */\n updatedAt: string;\n}\n\n/**\n * Complete locale configuration for the plugin\n */\nexport interface LocaleConfig {\n /** Array of configured locales */\n locales: LocaleDefinition[];\n /** Optional default locale code */\n defaultLocale?: string;\n /** Timestamp when configuration was last updated */\n lastUpdated: string;\n /** Configuration version for migration purposes */\n version: string;\n}\n\n/**\n * Validation result for locale operations\n */\nexport interface LocaleValidationResult {\n /** Whether the validation passed */\n isValid: boolean;\n /** Array of validation error messages */\n errors: string[];\n /** Array of validation warning messages */\n warnings: string[];\n}\n\n/**\n * Options for locale selection operations\n */\nexport interface LocaleSelectionOptions {\n /** Available locales to choose from */\n availableLocales: LocaleDefinition[];\n /** Currently selected locale codes */\n selectedLocales: string[];\n /** Whether multiple locales can be selected */\n allowMultiple: boolean;\n /** Whether selection is required (cannot be empty) */\n required: boolean;\n}\n\n/**\n * Locale code validation regex (ISO 639-1 + ISO 3166-1 format)\n * Format: two lowercase letters, hyphen, two uppercase letters (e.g., en-US, fr-FR)\n */\nexport const LOCALE_CODE_REGEX = /^[a-z]{2}-[A-Z]{2}$/;\n\n/**\n * Validates a locale code format\n * Requirements: 1.2, 1.3\n * \n * @param code - The locale code to validate\n * @returns True if the code matches ISO 639-1 + ISO 3166-1 format\n * \n * @example\n * validateLocaleCode('en-US') // true\n * validateLocaleCode('fr-FR') // true\n * validateLocaleCode('en_US') // false\n * validateLocaleCode('EN-US') // false\n * validateLocaleCode('e-US') // false\n */\nexport function validateLocaleCode(code: string): boolean {\n if (!code || typeof code !== 'string') {\n return false;\n }\n return LOCALE_CODE_REGEX.test(code);\n}\n\n/**\n * Validates a locale definition object\n * Requirements: 1.2, 1.3\n * \n * @param locale - The locale definition to validate\n * @returns Validation result with errors and warnings\n */\nexport function validateLocaleDefinition(locale: Partial<LocaleDefinition>): LocaleValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Validate code\n if (!locale.code) {\n errors.push('Locale code is required');\n } else if (!validateLocaleCode(locale.code)) {\n errors.push('Locale code must be in format: xx-XX (e.g., en-US, fr-FR)');\n }\n\n // Validate display name\n if (!locale.displayName) {\n errors.push('Display name is required');\n } else if (locale.displayName.trim().length === 0) {\n errors.push('Display name cannot be empty');\n } else if (locale.displayName.length > 100) {\n warnings.push('Display name is very long (over 100 characters)');\n }\n\n // Validate enabled flag\n if (locale.enabled !== undefined && typeof locale.enabled !== 'boolean') {\n errors.push('Enabled flag must be a boolean value');\n }\n\n // Validate timestamps if present\n if (locale.createdAt && !isValidISODate(locale.createdAt)) {\n errors.push('createdAt must be a valid ISO 8601 date string');\n }\n\n if (locale.updatedAt && !isValidISODate(locale.updatedAt)) {\n errors.push('updatedAt must be a valid ISO 8601 date string');\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n };\n}\n\n/**\n * Validates a locale configuration object\n * Requirements: 1.2, 1.3\n * \n * @param config - The locale configuration to validate\n * @returns Validation result with errors and warnings\n */\nexport function validateLocaleConfig(config: Partial<LocaleConfig>): LocaleValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Validate locales array\n if (!config.locales) {\n errors.push('Locales array is required');\n } else if (!Array.isArray(config.locales)) {\n errors.push('Locales must be an array');\n } else {\n // Validate each locale definition\n const localeCodes = new Set<string>();\n \n config.locales.forEach((locale, index) => {\n const localeValidation = validateLocaleDefinition(locale);\n \n if (!localeValidation.isValid) {\n errors.push(`Locale at index ${index}: ${localeValidation.errors.join(', ')}`);\n }\n \n if (localeValidation.warnings.length > 0) {\n warnings.push(`Locale at index ${index}: ${localeValidation.warnings.join(', ')}`);\n }\n\n // Check for duplicate locale codes\n if (locale.code) {\n if (localeCodes.has(locale.code)) {\n errors.push(`Duplicate locale code: ${locale.code}`);\n }\n localeCodes.add(locale.code);\n }\n });\n\n // Warn if no locales are configured\n if (config.locales.length === 0) {\n warnings.push('No locales configured - users will not be able to translate content');\n }\n }\n\n // Validate default locale if present\n if (config.defaultLocale) {\n if (!validateLocaleCode(config.defaultLocale)) {\n errors.push('Default locale must be in format: xx-XX (e.g., en-US)');\n } else if (config.locales && Array.isArray(config.locales)) {\n const defaultLocaleExists = config.locales.some(\n locale => locale.code === config.defaultLocale\n );\n if (!defaultLocaleExists) {\n warnings.push('Default locale is not in the configured locales list');\n }\n }\n }\n\n // Validate version\n if (!config.version) {\n errors.push('Configuration version is required');\n } else if (typeof config.version !== 'string') {\n errors.push('Configuration version must be a string');\n }\n\n // Validate lastUpdated\n if (!config.lastUpdated) {\n errors.push('lastUpdated timestamp is required');\n } else if (!isValidISODate(config.lastUpdated)) {\n errors.push('lastUpdated must be a valid ISO 8601 date string');\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n warnings\n };\n}\n\n/**\n * Checks if a locale code exists in a locale configuration\n * \n * @param config - The locale configuration to search\n * @param code - The locale code to find\n * @returns True if the locale code exists in the configuration\n */\nexport function localeExists(config: LocaleConfig, code: string): boolean {\n return config.locales.some(locale => locale.code === code);\n}\n\n/**\n * Gets enabled locales from a configuration\n * \n * @param config - The locale configuration\n * @returns Array of enabled locale definitions\n */\nexport function getEnabledLocales(config: LocaleConfig): LocaleDefinition[] {\n return config.locales.filter(locale => locale.enabled);\n}\n\n/**\n * Finds a locale definition by code\n * \n * @param config - The locale configuration to search\n * @param code - The locale code to find\n * @returns The locale definition or undefined if not found\n */\nexport function findLocaleByCode(config: LocaleConfig, code: string): LocaleDefinition | undefined {\n return config.locales.find(locale => locale.code === code);\n}\n\n/**\n * Helper function to validate ISO 8601 date strings\n * \n * @param dateString - The date string to validate\n * @returns True if the string is a valid ISO 8601 date\n */\nfunction isValidISODate(dateString: string): boolean {\n if (!dateString || typeof dateString !== 'string') {\n return false;\n }\n \n const date = new Date(dateString);\n return date instanceof Date && !isNaN(date.getTime()) && date.toISOString() === dateString;\n}","/**\n * Custom Radio Input Component with Auto-Default\n * \n * This component wraps Sanity's default radio input and automatically sets\n * the default value when the field is undefined. This ensures that:\n * 1. New users see defaults immediately\n * 2. Existing users with legacy configs see defaults without manual intervention\n * 3. The UX is seamless and doesn't require any user action\n */\n\nimport React, { useEffect } from 'react';\nimport { StringInputProps, set } from 'sanity';\n\ninterface RadioWithDefaultProps extends StringInputProps {\n defaultValue: string;\n}\n\nexport const RadioWithDefault: React.FC<RadioWithDefaultProps> = (props) => {\n const { value, onChange, defaultValue, renderDefault } = props;\n\n // Auto-set default value when field is undefined or empty\n useEffect(() => {\n if (value === undefined || value === null || value === '') {\n // Automatically set the default value without user intervention\n onChange(set(defaultValue));\n }\n }, [value, defaultValue, onChange]);\n\n // Render the default radio input with the current or default value\n return renderDefault({\n ...props,\n // Use the actual value if set, otherwise show default while patch is applying\n value: value !== undefined && value !== null && value !== '' ? value : defaultValue\n });\n};\n\nRadioWithDefault.displayName = 'RadioWithDefault';\n\n","/**\n * Plugin configuration schema and utilities\n * Requirements: 5.1, 5.2, 5.3\n */\n\nimport { LocaleConfig, LocaleDefinition } from '../types/locale';\nimport { RadioWithDefault } from '../components/RadioWithDefault';\n\n/**\n * Create unified plugin configuration schema for Sanity\n * Internal type prefixed with EL_ to separate from customer document types\n * \n * This single document type stores all plugin configuration:\n * - OAuth/authentication settings\n * - Locale definitions\n * - DNT (Do Not Translate) field mappings by document type\n * \n * @param PasswordInputComponent - Optional password input component for access token field\n */\nexport const createPluginConfigSchema = (PasswordInputComponent?: any) => ({\n name: 'EL_PluginConfiguration',\n title: 'Easyling Translation Plugin Configuration',\n type: 'document',\n fields: [\n // OAuth Configuration\n {\n name: 'projectId',\n title: 'Project ID',\n type: 'string',\n description: 'Easyling project identifier',\n group: 'oauth'\n },\n {\n name: 'accessToken',\n title: 'Access Token',\n type: 'string',\n description: 'Easyling API access token (hidden for security)',\n group: 'oauth',\n ...(PasswordInputComponent && {\n components: {\n input: PasswordInputComponent\n }\n })\n },\n \n // Translation Settings\n {\n name: 'translationApiEndpoint',\n title: 'Translation API Endpoint',\n type: 'string',\n description: 'The URL where translation requests will be sent (defaults to https://app.easyling.com/_el/ext/direct/sanity if not set)',\n initialValue: 'https://app.easyling.com/_el/ext/direct/sanity',\n placeholder: 'https://app.easyling.com/_el/ext/direct/sanity',\n group: 'translation',\n validation: (Rule: any) => Rule.custom((value: string) => {\n // Optional field - if empty, will use default\n if (!value || value.trim() === '') {\n return true;\n }\n try {\n const url = new URL(value.trim());\n if (!['http:', 'https:'].includes(url.protocol)) {\n return 'Must be a valid HTTP or HTTPS URL';\n }\n return true;\n } catch (error) {\n return 'Must be a valid HTTP or HTTPS URL';\n }\n })\n },\n {\n name: 'defaultDocumentCreationMode',\n title: 'Default Document Creation Mode',\n type: 'string',\n description: 'Whether translated documents should be created as drafts or published by default',\n initialValue: 'draft',\n group: 'translation',\n options: {\n list: [\n { title: 'Draft', value: 'draft' },\n { title: 'Published', value: 'published' }\n ],\n layout: 'radio'\n },\n components: {\n input: (props: any) => RadioWithDefault({ ...props, defaultValue: 'draft' })\n }\n },\n \n // Collision Resolution Settings\n {\n name: 'collisionResolutionMode',\n title: 'Collision Resolution Mode',\n type: 'string',\n description: 'How to handle existing translated documents when a translation already exists for the same source document and target locale',\n initialValue: 'replace',\n group: 'translation',\n options: {\n list: [\n { title: 'Replace existing translated document', value: 'replace' },\n { title: 'Create new translated document', value: 'create' }\n ],\n layout: 'radio'\n },\n components: {\n input: (props: any) => RadioWithDefault({ ...props, defaultValue: 'replace' })\n }\n },\n {\n name: 'existingDocumentHandling',\n title: 'Existing Document Handling',\n type: 'string',\n description: 'When creating a new translated document, how should the existing translated document be handled? (Only applies when \"Create new\" mode is selected)',\n initialValue: 'draft',\n group: 'translation',\n options: {\n list: [\n { title: 'Set the existing document to draft', value: 'draft' },\n { title: 'Delete the existing document', value: 'delete' }\n ],\n layout: 'radio'\n },\n components: {\n input: (props: any) => RadioWithDefault({ ...props, defaultValue: 'draft' })\n },\n hidden: ({ parent }: { parent?: { collisionResolutionMode?: string } }) => \n parent?.collisionResolutionMode !== 'create'\n },\n \n // Advanced Settings\n {\n name: 'requestContentType',\n title: 'Request Content-Type',\n type: 'string',\n description: 'Serialization format for translation request payloads',\n initialValue: 'application/json',\n group: 'advanced',\n options: {\n list: [\n { title: 'JSON', value: 'application/json' },\n { title: 'Protocol Buffer', value: 'application/x-protobuf' }\n ],\n layout: 'radio'\n },\n components: {\n input: (props: any) => RadioWithDefault({ ...props, defaultValue: 'application/json' })\n }\n },\n {\n name: 'responseAcceptHeader',\n title: 'Response Accept Header',\n type: 'string',\n description: 'Preferred format for translation response (content negotiation)',\n initialValue: 'application/json',\n group: 'advanced',\n options: {\n list: [\n { title: 'JSON', value: 'application/json' },\n { title: 'Protocol Buffer', value: 'application/x-protobuf' }\n ],\n layout: 'radio'\n },\n components: {\n input: (props: any) => RadioWithDefault({ ...props, defaultValue: 'application/json' })\n }\n },\n \n // Locale Configuration\n {\n name: 'locales',\n title: 'Available Locales',\n type: 'array',\n description: 'Configure the locales available for translation',\n group: 'locales',\n of: [\n {\n type: 'object',\n name: 'localeItem',\n title: 'Locale',\n fields: [\n {\n name: 'code',\n title: 'Locale Code',\n type: 'string',\n description: 'Locale code in ISO 639-1 + ISO 3166-1 format (e.g., en-US, fr-FR)',\n validation: (Rule: any) => Rule\n .required()\n .regex(/^[a-z]{2}-[A-Z]{2}$/, {\n name: 'locale-code',\n invert: false\n })\n .error('Locale code must be in format: xx-XX (e.g., en-US, fr-FR)')\n },\n {\n name: 'displayName',\n title: 'Display Name',\n type: 'string',\n description: 'Human-readable name for this locale (e.g., English (United States))',\n validation: (Rule: any) => Rule\n .required()\n .min(1)\n .error('Display name is required')\n },\n {\n name: 'enabled',\n title: 'Enabled',\n type: 'boolean',\n description: 'Whether this locale is available for translation',\n initialValue: true\n },\n {\n name: 'createdAt',\n title: 'Created At',\n type: 'string',\n hidden: true\n },\n {\n name: 'updatedAt',\n title: 'Updated At',\n type: 'string',\n hidden: true\n }\n ],\n preview: {\n select: {\n title: 'displayName',\n subtitle: 'code',\n enabled: 'enabled'\n },\n prepare: ({ title, subtitle, enabled }: any) => ({\n title: title || 'Unnamed Locale',\n subtitle: subtitle ? `${subtitle}${enabled === false ? ' (Disabled)' : ''}` : ''\n })\n }\n }\n ]\n },\n {\n name: 'defaultLocale',\n title: 'Default Locale',\n type: 'string',\n description: 'Default locale code to use when none is specified',\n group: 'locales',\n validation: (Rule: any) => Rule\n .regex(/^[a-z]{2}-[A-Z]{2}$/, {\n name: 'locale-code',\n invert: false\n })\n .error('Default locale must be in format: xx-XX (e.g., en-US)')\n },\n \n // Debug Mode\n {\n name: 'debugMode',\n title: 'Debug Mode',\n type: 'boolean',\n description: 'When enabled, displays additional DNT status badges on all fields to help debug translation settings. The debug badge shows the effective DNT status that will be sent in translation requests.',\n initialValue: false,\n group: 'advanced'\n },\n \n // DNT Field Configuration\n {\n name: 'dntFieldConfigurations',\n title: 'DNT Field Configurations',\n type: 'array',\n description: 'Document type DNT (Do Not Translate) field configurations. When you mark a field as DNT for a document type, it applies to all documents of that type. This is automatically managed when you toggle DNT badges in documents.',\n group: 'dnt',\n readOnly: true, // Read-only in UI - managed through DNT badge components\n of: [\n {\n type: 'object',\n name: 'dntTypeConfig',\n title: 'Document Type DNT Configuration',\n fields: [\n {\n name: 'documentType',\n title: 'Document Type',\n type: 'string',\n description: 'The document type (e.g., \"product\", \"article\")',\n validation: (Rule: any) => Rule.required()\n },\n {\n name: 'fields',\n title: 'DNT Fields',\n type: 'array',\n description: 'Fields marked as Do Not Translate',\n of: [\n {\n type: 'object',\n name: 'dntField',\n fields: [\n {\n name: 'fieldPath',\n title: 'Field Path',\n type: 'string',\n description: 'The field path (e.g., \"sku\", \"price\")',\n validation: (Rule: any) => Rule.required()\n },\n {\n name: 'dnt',\n title: 'Do Not Translate',\n type: 'boolean',\n description: 'Whether this field should not be translated',\n initialValue: true\n }\n ],\n preview: {\n select: {\n fieldPath: 'fieldPath',\n dnt: 'dnt'\n },\n prepare: ({ fieldPath, dnt }: any) => ({\n title: fieldPath || 'Unknown field',\n subtitle: dnt ? 'Do Not Translate' : 'Translatable'\n })\n }\n }\n ]\n }\n ],\n preview: {\n select: {\n documentType: 'documentType',\n fields: 'fields'\n },\n prepare: ({ documentType, fields }: any) => ({\n title: documentType || 'Unknown type',\n subtitle: fields ? `${fields.length} DNT field${fields.length !== 1 ? 's' : ''}` : 'No DNT fields'\n })\n }\n }\n ]\n },\n \n // Metadata\n {\n name: 'version',\n title: 'Configuration Version',\n type: 'string',\n description: 'Internal version for configuration migration',\n initialValue: '1.0.0',\n readOnly: true,\n hidden: true\n },\n {\n name: 'lastUpdated',\n title: 'Last Updated',\n type: 'datetime',\n description: 'When this configuration was last modified',\n readOnly: true,\n hidden: true\n }\n ],\n groups: [\n {\n name: 'oauth',\n title: 'Authentication',\n default: true\n },\n {\n name: 'translation',\n title: 'Translation Settings'\n },\n {\n name: 'locales',\n title: 'Locales'\n },\n {\n name: 'dnt',\n title: 'DNT Field Configuration',\n description: 'View DNT (Do Not Translate) settings for all document types'\n },\n {\n name: 'advanced',\n title: '☢️ CAUTION ☢️ Dangerous Advanced Settings',\n description: 'Advanced developer settings for request/response serialization. Changing these settings may break compatibility with your translation service.'\n }\n ],\n preview: {\n prepare: () => ({\n title: 'Easyling Translation Plugin Configuration',\n subtitle: 'OAuth, Translation Settings, Locales, and DNT field settings'\n })\n }\n});\n\n/**\n * Default export for backward compatibility and tests\n */\nexport const pluginConfigSchema = createPluginConfigSchema();\n\n/**\n * Legacy locale-only configuration schema (deprecated, kept for migration)\n * @deprecated Use pluginConfigSchema instead\n */\nexport const legacyLocaleConfigSchema = {\n name: 'EL_translation-plugin-config',\n title: 'Translation Plugin Configuration (Legacy)',\n type: 'object',\n fields: [\n {\n name: 'locales',\n title: 'Available Locales',\n type: 'array',\n description: 'Configure the locales available for translation',\n of: [\n {\n type: 'object',\n title: 'Locale',\n fields: [\n {\n name: 'code',\n title: 'Locale Code',\n type: 'string',\n description: 'Locale code in ISO 639-1 + ISO 3166-1 format (e.g., en-US, fr-FR)',\n validation: (Rule: any) => Rule\n .required()\n .regex(/^[a-z]{2}-[A-Z]{2}$/, {\n name: 'locale-code',\n invert: false\n })\n .error('Locale code must be in format: xx-XX (e.g., en-US, fr-FR)')\n },\n {\n name: 'displayName',\n title: 'Display Name',\n type: 'string',\n description: 'Human-readable name for this locale (e.g., English (United States))',\n validation: (Rule: any) => Rule\n .required()\n .min(1)\n .error('Display name is required')\n },\n {\n name: 'enabled',\n title: 'Enabled',\n type: 'boolean',\n description: 'Whether this locale is available for translation',\n initialValue: true\n }\n ],\n preview: {\n select: {\n title: 'displayName',\n subtitle: 'code',\n enabled: 'enabled'\n },\n prepare: ({ title, subtitle, enabled }: any) => ({\n title: title || 'Unnamed Locale',\n subtitle: `${subtitle}${enabled ? '' : ' (Disabled)'}`,\n media: enabled ? '🌐' : '🚫'\n })\n }\n }\n ]\n },\n {\n name: 'defaultLocale',\n title: 'Default Locale',\n type: 'string',\n description: 'Default locale code to use when none is specified',\n validation: (Rule: any) => Rule\n .regex(/^[a-z]{2}-[A-Z]{2}$/, {\n name: 'locale-code',\n invert: false\n })\n .error('Default locale must be in format: xx-XX (e.g., en-US)')\n },\n {\n name: 'version',\n title: 'Configuration Version',\n type: 'string',\n description: 'Internal version for configuration migration',\n initialValue: '1.0.0',\n readOnly: true\n }\n ]\n};\n\n/**\n * Default locale configuration\n */\nexport const defaultLocaleConfig: LocaleConfig = {\n locales: [],\n version: '1.0.0',\n lastUpdated: new Date().toISOString()\n};\n\n/**\n * Common locale definitions for quick setup\n */\nexport const commonLocales: LocaleDefinition[] = [\n {\n code: 'en-US',\n displayName: 'English (United States)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'en-GB',\n displayName: 'English (United Kingdom)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'es-ES',\n displayName: 'Spanish (Spain)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'es-MX',\n displayName: 'Spanish (Mexico)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'fr-FR',\n displayName: 'French (France)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'de-DE',\n displayName: 'German (Germany)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'it-IT',\n displayName: 'Italian (Italy)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'pt-BR',\n displayName: 'Portuguese (Brazil)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'ja-JP',\n displayName: 'Japanese (Japan)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'ko-KR',\n displayName: 'Korean (South Korea)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'zh-CN',\n displayName: 'Chinese (Simplified)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n },\n {\n code: 'zh-TW',\n displayName: 'Chinese (Traditional)',\n enabled: true,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString()\n }\n];\n\n/**\n * Validate locale code format\n */\nexport function validateLocaleCode(code: string): boolean {\n const localeCodeRegex = /^[a-z]{2}-[A-Z]{2}$/;\n return localeCodeRegex.test(code);\n}\n\n/**\n * Create a new locale definition with current timestamps\n */\nexport function createLocaleDefinition(\n code: string,\n displayName: string,\n enabled: boolean = true\n): LocaleDefinition {\n const now = new Date().toISOString();\n return {\n code,\n displayName,\n enabled,\n createdAt: now,\n updatedAt: now\n };\n}\n\n/**\n * Update an existing locale definition with new timestamp\n */\nexport function updateLocaleDefinition(\n locale: LocaleDefinition,\n updates: Partial<Omit<LocaleDefinition, 'createdAt' | 'updatedAt'>>\n): LocaleDefinition {\n return {\n ...locale,\n ...updates,\n updatedAt: new Date().toISOString()\n };\n}","/**\n * Locale configuration management service\n * Requirements: 1.1, 1.4, 1.5, 5.4, 5.5, 5.6\n * \n * Provides CRUD operations for locale configuration management with validation,\n * persistence, and error handling capabilities.\n */\n\nimport {\n LocaleConfig,\n LocaleDefinition,\n LocaleValidationResult,\n validateLocaleDefinition,\n validateLocaleConfig,\n localeExists,\n findLocaleByCode\n} from '../types/locale';\nimport { defaultLocaleConfig } from '../config/pluginConfig';\n\n/**\n * Storage interface for locale configuration persistence\n * This allows for different storage implementations (localStorage, Sanity config, etc.)\n */\nexport interface LocaleStorageAdapter {\n load(): Promise<LocaleConfig | null>;\n save(config: LocaleConfig): Promise<void>;\n}\n\n/**\n * Error types for locale service operations\n */\nexport class LocaleServiceError extends Error {\n constructor(\n message: string,\n public code: string,\n public details?: unknown\n ) {\n super(message);\n this.name = 'LocaleServiceError';\n }\n}\n\n/**\n * Service for managing locale configuration with CRUD operations\n * Requirements: 1.1, 1.4, 1.5, 5.4, 5.5, 5.6\n */\nexport class LocaleService {\n private config: LocaleConfig;\n private storageAdapter: LocaleStorageAdapter | null;\n\n /**\n * Creates a new LocaleService instance\n * \n * @param storageAdapter - Optional storage adapter for persistence\n * @param initialConfig - Optional initial configuration (defaults to empty config)\n */\n constructor(\n storageAdapter: LocaleStorageAdapter | null = null,\n initialConfig?: LocaleConfig\n ) {\n this.storageAdapter = storageAdapter;\n this.config = initialConfig || {\n ...defaultLocaleConfig,\n locales: [...defaultLocaleConfig.locales]\n };\n }\n\n /**\n * Loads locale configuration from storage\n * Requirements: 1.4, 5.4\n * \n * @returns Promise resolving to the loaded configuration\n * @throws LocaleServiceError if loading fails\n */\n async loadConfig(): Promise<LocaleConfig> {\n try {\n if (!this.storageAdapter) {\n // No storage adapter, return current in-memory config\n return this.config;\n }\n\n const loadedConfig = await this.storageAdapter.load();\n\n if (loadedConfig) {\n // Validate loaded configuration\n const validation = validateLocaleConfig(loadedConfig);\n \n if (!validation.isValid) {\n // Configuration is corrupted, reset to default\n console.error('Loaded configuration is invalid:', validation.errors);\n throw new LocaleServiceError(\n 'Configuration is corrupted and cannot be loaded',\n 'CONFIG_CORRUPTED',\n { errors: validation.errors }\n );\n }\n\n this.config = loadedConfig;\n return this.config;\n }\n\n // No configuration exists, initialize with default\n this.config = { ...defaultLocaleConfig };\n return this.config;\n } catch (error) {\n if (error instanceof LocaleServiceError) {\n throw error;\n }\n\n throw new LocaleServiceError(\n 'Failed to load locale configuration',\n 'LOAD_FAILED',\n { originalError: error }\n );\n }\n }\n\n /**\n * Saves locale configuration to storage\n * Requirements: 1.5, 5.5\n * \n * @param config - Optional configuration to save (defaults to current config)\n * @returns Promise resolving when save is complete\n * @throws LocaleServiceError if saving fails\n */\n async saveConfig(config?: LocaleConfig): Promise<void> {\n try {\n const configToSave = config || this.config;\n\n // Validate configuration before saving\n const validation = validateLocaleConfig(configToSave);\n \n if (!validation.isValid) {\n throw new LocaleServiceError(\n 'Cannot save invalid configuration',\n 'INVALID_CONFIG',\n { errors: validation.errors }\n );\n }\n\n // Update lastUpdated timestamp\n configToSave.lastUpdated = new Date().toISOString();\n\n if (this.storageAdapter) {\n await this.storageAdapter.save(configToSave);\n }\n\n this.config = configToSave;\n } catch (error) {\n if (error instanceof LocaleServiceError) {\n throw error;\n }\n\n throw new LocaleServiceError(\n 'Failed to save locale configuration',\n 'SAVE_FAILED',\n { originalError: error }\n );\n }\n }\n\n /**\n * Gets the current locale configuration\n * \n * @returns Current locale configuration\n */\n getConfig(): LocaleConfig {\n return { ...this.config };\n }\n\n /**\n * Gets all locales from the configuration\n * \n * @returns Array of all locale definitions\n */\n getAllLocales(): LocaleDefinition[] {\n return [...this.config.locales];\n }\n\n /**\n * Gets all enabled locales from the configuration\n * \n * @returns Array of enabled locale definitions\n */\n getEnabledLocales(): LocaleDefinition[] {\n return this.config.locales.filter(locale => locale.enabled);\n }\n\n /**\n * Gets a locale by its code\n * \n * @param code - Locale code to find\n * @returns Locale definition or undefined if not found\n */\n getLocaleByCode(code: string): LocaleDefinition | undefined {\n return findLocaleByCode(this.config, code);\n }\n\n /**\n * Checks if a locale code exists in the configuration\n * \n * @param code - Locale code to check\n * @returns True if the locale exists\n */\n hasLocale(code: string): boolean {\n return localeExists(this.config, code);\n }\n\n /**\n * Adds a new locale to the configuration\n * Requirements: 1.1, 1.2, 1.3\n * \n * @param locale - Locale definition to add\n * @returns Promise resolving to validation result\n * @throws LocaleServiceError if locale is invalid or already exists\n */\n async addLocale(locale: Omit<LocaleDefinition, 'createdAt' | 'updatedAt'>): Promise<LocaleValidationResult> {\n // Validate locale definition\n const now = new Date().toISOString();\n const fullLocale: LocaleDefinition = {\n ...locale,\n createdAt: now,\n updatedAt: now\n };\n\n const validation = validateLocaleDefinition(fullLocale);\n \n if (!validation.isValid) {\n throw new LocaleServiceError(\n 'Cannot add invalid locale',\n 'INVALID_LOCALE',\n { errors: validation.errors }\n );\n }\n\n // Check for duplicate locale code\n if (this.hasLocale(locale.code)) {\n throw new LocaleServiceError(\n `Locale with code '${locale.code}' already exists`,\n 'DUPLICATE_LOCALE',\n { code: locale.code }\n );\n }\n\n // Add locale to configuration\n this.config.locales.push(fullLocale);\n\n // Save configuration\n await this.saveConfig();\n\n return validation;\n }\n\n /**\n * Updates an existing locale in the configuration\n * Requirements: 1.6, 1.7\n * \n * @param code - Code of the locale to update\n * @param updates - Partial locale definition with updates\n * @returns Promise resolving to validation result\n * @throws LocaleServiceError if locale not found or updates are invalid\n */\n async updateLocale(\n code: string,\n updates: Partial<Omit<LocaleDefinition, 'code' | 'createdAt' | 'updatedAt'>>\n ): Promise<LocaleValidationResult> {\n const localeIndex = this.config.locales.findIndex(l => l.code === code);\n\n if (localeIndex === -1) {\n throw new LocaleServiceError(\n `Locale with code '${code}' not found`,\n 'LOCALE_NOT_FOUND',\n { code }\n );\n }\n\n const existingLocale = this.config.locales[localeIndex];\n const updatedLocale: LocaleDefinition = {\n ...existingLocale,\n ...updates,\n code: existingLocale.code, // Preserve original code\n createdAt: existingLocale.createdAt, // Preserve creation timestamp\n updatedAt: new Date().toISOString()\n };\n\n // Validate updated locale\n const validation = validateLocaleDefinition(updatedLocale);\n \n if (!validation.isValid) {\n throw new LocaleServiceError(\n 'Cannot update locale with invalid data',\n 'INVALID_LOCALE',\n { errors: validation.errors }\n );\n }\n\n // Update locale in configuration\n this.config.locales[localeIndex] = updatedLocale;\n\n // Save configuration\n await this.saveConfig();\n\n return validation;\n }\n\n /**\n * Removes a locale from the configuration\n * Requirements: 1.6\n * \n * @param code - Code of the locale to remove\n * @returns Promise resolving when removal is complete\n * @throws LocaleServiceError if locale not found\n */\n async removeLocale(code: string): Promise<void> {\n const localeIndex = this.config.locales.findIndex(l => l.code === code);\n\n if (localeIndex === -1) {\n throw new LocaleServiceError(\n `Locale with code '${code}' not found`,\n 'LOCALE_NOT_FOUND',\n { code }\n );\n }\n\n // Remove locale from configuration\n this.config.locales.splice(localeIndex, 1);\n\n // If removed locale was the default, clear default locale\n if (this.config.defaultLocale === code) {\n this.config.defaultLocale = undefined;\n }\n\n // Save configuration\n await this.saveConfig();\n }\n\n /**\n * Sets the default locale\n * \n * @param code - Code of the locale to set as default\n * @returns Promise resolving when update is complete\n * @throws LocaleServiceError if locale not found\n */\n async setDefaultLocale(code: string): Promise<void> {\n if (!this.hasLocale(code)) {\n throw new LocaleServiceError(\n `Cannot set default locale: locale with code '${code}' not found`,\n 'LOCALE_NOT_FOUND',\n { code }\n );\n }\n\n this.config.defaultLocale = code;\n await this.saveConfig();\n }\n\n /**\n * Clears the default locale\n * \n * @returns Promise resolving when update is complete\n */\n async clearDefaultLocale(): Promise<void> {\n this.config.defaultLocale = undefined;\n await this.saveConfig();\n }\n\n /**\n * Validates the current configuration\n * Requirements: 5.6\n * \n * @returns Validation result\n */\n validateCurrentConfig(): LocaleValidationResult {\n return validateLocaleConfig(this.config);\n }\n\n /**\n * Resets configuration to default state\n * Requirements: 5.6\n * \n * @returns Promise resolving when reset is complete\n */\n async resetToDefault(): Promise<void> {\n this.config = { ...defaultLocaleConfig };\n await this.saveConfig();\n }\n\n /**\n * Imports a locale configuration\n * Useful for bulk import or migration scenarios\n * \n * @param config - Configuration to import\n * @returns Promise resolving to validation result\n * @throws LocaleServiceError if configuration is invalid\n */\n async importConfig(config: LocaleConfig): Promise<LocaleValidationResult> {\n const validation = validateLocaleConfig(config);\n \n if (!validation.isValid) {\n throw new LocaleServiceError(\n 'Cannot import invalid configuration',\n 'INVALID_CONFIG',\n { errors: validation.errors }\n );\n }\n\n this.config = { ...config };\n await this.saveConfig();\n\n return validation;\n }\n\n /**\n * Exports the current locale configuration\n * \n * @returns Current configuration as a plain object\n */\n exportConfig(): LocaleConfig {\n return { ...this.config };\n }\n}","/**\n * Locale Storage Adapter for Sanity Configuration\n * Requirements: 5.1, 5.2, 5.3, 5.7\n * \n * Now delegates to UnifiedConfigStorage for centralized configuration management.\n * Locale settings are stored in the EL_PluginConfiguration document alongside\n * OAuth and DNT configurations.\n */\n\nimport { SanityClient } from 'sanity';\nimport { LocaleConfig } from '../types/locale';\nimport { LocaleStorageAdapter } from './localeService';\nimport { UnifiedConfigStorage } from './unifiedConfigStorage';\n\n/**\n * Legacy configuration document ID (deprecated)\n * @deprecated Now uses unified configuration\n */\nconst LEGACY_LOCALE_CONFIG_DOC_ID = 'sanity-translation-plugin.locale-config';\n\n/**\n * Locale configuration storage adapter\n * Now uses UnifiedConfigStorage for centralized management\n * Requirements: 5.1, 5.2, 5.3, 5.7\n */\nexport class SanityLocaleStorageAdapter implements LocaleStorageAdapter {\n private unifiedStorage: UnifiedConfigStorage;\n private client: SanityClient;\n\n constructor(client: SanityClient) {\n this.client = client;\n this.unifiedStorage = new UnifiedConfigStorage(client);\n }\n\n /**\n * Load locale configuration from unified storage\n * Requirements: 5.2, 5.4\n */\n async load(): Promise<LocaleConfig | null> {\n try {\n // Try loading from unified configuration first\n const config = await this.unifiedStorage.loadLocale();\n \n if (config && config.locales && config.locales.length > 0) {\n console.log('Loaded locale configuration from unified storage');\n return config;\n }\n\n // Try migrating from legacy storage\n const legacyConfig = await this.loadLegacy();\n if (legacyConfig) {\n console.log('Migrating locale configuration from legacy storage...');\n await this.save(legacyConfig);\n await this.deleteLegacy();\n console.log('Locale configuration migration complete');\n return legacyConfig;\n }\n\n console.log('No locale configuration found');\n return null;\n } catch (error) {\n console.error('Failed to load locale configuration:', error);\n throw error;\n }\n }\n\n /**\n * Save locale configuration to unified storage\n * Requirements: 5.3, 5.5\n */\n async save(config: LocaleConfig): Promise<void> {\n try {\n await this.unifiedStorage.saveLocale(config);\n console.log('Saved locale configuration to unified storage');\n } catch (error) {\n console.error('Failed to save locale configuration:', error);\n throw error;\n }\n }\n\n // Legacy migration methods\n\n /**\n * Load from legacy locale-specific document\n * @private\n */\n private async loadLegacy(): Promise<LocaleConfig | null> {\n try {\n const doc = await this.client.fetch<LocaleConfig | null>(\n `*[_id == $id][0]`,\n { id: LEGACY_LOCALE_CONFIG_DOC_ID }\n );\n\n if (!doc) {\n return null;\n }\n\n return {\n locales: doc.locales || [],\n defaultLocale: doc.defaultLocale,\n version: doc.version || '1.0.0',\n lastUpdated: doc.lastUpdated || new Date().toISOString()\n };\n } catch (error) {\n console.error('Failed to load legacy locale configuration:', error);\n return null;\n }\n }\n\n /**\n * Delete legacy locale document after migration\n * @private\n */\n private async deleteLegacy(): Promise<void> {\n try {\n await this.client.delete(LEGACY_LOCALE_CONFIG_DOC_ID);\n console.log('Deleted legacy locale configuration document');\n } catch (error) {\n console.warn('Failed to delete legacy locale document:', error);\n // Non-fatal - migration already succeeded\n }\n }\n}\n","/**\n * ConfirmationDialog Component\n * Requirements: 3.1, 3.2, 3.8\n * \n * A reusable confirmation dialog with proper accessibility support\n */\n\nimport React, { useEffect, useRef } from 'react';\nimport { Dialog, Box, Stack, Text, Button, Card } from '@sanity/ui';\nimport type { ConfirmationDialogOptions } from '../../types/dialog';\n\nexport interface ConfirmationDialogProps extends ConfirmationDialogOptions {\n /** Whether the dialog is open */\n open: boolean;\n /** Callback when user confirms */\n onConfirm: () => void;\n /** Callback when user cancels */\n onCancel: () => void;\n}\n\n/**\n * ConfirmationDialog component with accessibility features\n */\nexport const ConfirmationDialog: React.FC<ConfirmationDialogProps> = ({\n open,\n title,\n message,\n details,\n confirmText = 'Confirm',\n cancelText = 'Cancel',\n tone = 'primary',\n closable = true,\n onConfirm,\n onCancel,\n}) => {\n const confirmButtonRef = useRef<HTMLButtonElement>(null);\n\n // Focus the confirm button when dialog opens\n useEffect(() => {\n if (open && confirmButtonRef.current) {\n // Small delay to ensure dialog is fully rendered\n setTimeout(() => {\n confirmButtonRef.current?.focus();\n }, 100);\n }\n }, [open]);\n\n if (!open) return null;\n\n return (\n <Dialog\n id=\"confirmation-dialog\"\n header={title}\n onClose={closable ? onCancel : undefined}\n onClickOutside={closable ? onCancel : undefined}\n width={1}\n role=\"alertdialog\"\n aria-labelledby=\"confirmation-dialog-title\"\n aria-describedby=\"confirmation-dialog-description\"\n >\n <Box padding={4}>\n <Stack space={4}>\n <Card>\n <Box padding={3}>\n <Stack space={3}>\n <Text\n id=\"confirmation-dialog-description\"\n size={2}\n weight=\"regular\"\n >\n {message}\n </Text>\n {details && (\n <Text size={1} muted>\n {details}\n </Text>\n )}\n </Stack>\n </Box>\n </Card>\n\n <Stack space={2}>\n <Button\n ref={confirmButtonRef}\n text={confirmText}\n tone={tone}\n onClick={onConfirm}\n mode=\"default\"\n aria-label={`${confirmText} action`}\n />\n <Button\n text={cancelText}\n tone=\"default\"\n onClick={onCancel}\n mode=\"ghost\"\n aria-label={`${cancelText} action`}\n />\n </Stack>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","/**\n * SuccessDialog Component\n * Requirements: 3.6, 3.8\n * \n * A success notification dialog with accessibility support\n */\n\nimport React, { useEffect, useRef } from 'react';\nimport { Dialog, Box, Stack, Text, Button, Card } from '@sanity/ui';\nimport { CheckmarkCircleIcon } from '@sanity/icons';\nimport type { SuccessDialogOptions } from '../../types/dialog';\n\nexport interface SuccessDialogProps extends SuccessDialogOptions {\n /** Whether the dialog is open */\n open: boolean;\n /** Callback when dialog is closed */\n onClose: () => void;\n}\n\n/**\n * SuccessDialog component for displaying success messages\n */\nexport const SuccessDialog: React.FC<SuccessDialogProps> = ({\n open,\n title,\n message,\n details,\n autoCloseTimeout,\n closable = true,\n onClose,\n}) => {\n const closeButtonRef = useRef<HTMLButtonElement>(null);\n\n // Focus the close button when dialog opens\n useEffect(() => {\n if (open && closeButtonRef.current) {\n setTimeout(() => {\n closeButtonRef.current?.focus();\n }, 100);\n }\n }, [open]);\n\n // Auto-close functionality\n useEffect(() => {\n if (!open || !autoCloseTimeout) return;\n\n const timer = setTimeout(() => {\n onClose();\n }, autoCloseTimeout);\n\n return () => clearTimeout(timer);\n }, [open, autoCloseTimeout, onClose]);\n\n if (!open) return null;\n\n return (\n <Dialog\n id=\"success-dialog\"\n header={title}\n onClose={closable ? onClose : undefined}\n onClickOutside={closable ? onClose : undefined}\n width={1}\n role=\"dialog\"\n aria-labelledby=\"success-dialog-title\"\n aria-describedby=\"success-dialog-description\"\n >\n <Box padding={4}>\n <Stack space={4}>\n <Card tone=\"positive\" padding={3} radius={2}>\n <Stack space={3}>\n <Box>\n <Text size={3}>\n <CheckmarkCircleIcon />\n </Text>\n </Box>\n <Text\n id=\"success-dialog-description\"\n size={2}\n weight=\"regular\"\n >\n {message}\n </Text>\n {details && (\n <Text size={1} muted>\n {details}\n </Text>\n )}\n </Stack>\n </Card>\n\n <Button\n ref={closeButtonRef}\n text=\"Close\"\n tone=\"positive\"\n onClick={onClose}\n mode=\"default\"\n aria-label=\"Close success dialog\"\n />\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","/**\n * ErrorDialog Component\n * Requirements: 3.7, 3.8\n * \n * An error notification dialog with accessibility support and retry functionality\n */\n\nimport React, { useEffect, useRef } from 'react';\nimport { Dialog, Box, Stack, Text, Button, Card, Code } from '@sanity/ui';\nimport { ErrorOutlineIcon } from '@sanity/icons';\nimport type { ErrorDialogOptions } from '../../types/dialog';\n\nexport interface ErrorDialogProps extends ErrorDialogOptions {\n /** Whether the dialog is open */\n open: boolean;\n /** Callback when dialog is closed */\n onClose: () => void;\n /** Callback when user clicks retry */\n onRetry?: () => void;\n}\n\n/**\n * ErrorDialog component for displaying error messages\n */\nexport const ErrorDialog: React.FC<ErrorDialogProps> = ({\n open,\n title,\n message,\n error,\n showRetry = false,\n retryText = 'Retry',\n closable = true,\n onClose,\n onRetry,\n}) => {\n const primaryButtonRef = useRef<HTMLButtonElement>(null);\n\n // Focus the primary button when dialog opens\n useEffect(() => {\n if (open && primaryButtonRef.current) {\n setTimeout(() => {\n primaryButtonRef.current?.focus();\n }, 100);\n }\n }, [open]);\n\n if (!open) return null;\n\n return (\n <Dialog\n id=\"error-dialog\"\n header={title}\n onClose={closable ? onClose : undefined}\n onClickOutside={closable ? onClose : undefined}\n width={1}\n role=\"alertdialog\"\n aria-labelledby=\"error-dialog-title\"\n aria-describedby=\"error-dialog-description\"\n >\n <Box padding={4}>\n <Stack space={4}>\n <Card tone=\"critical\" padding={3} radius={2}>\n <Stack space={3}>\n <Box>\n <Text size={3}>\n <ErrorOutlineIcon />\n </Text>\n </Box>\n <Text\n id=\"error-dialog-description\"\n size={2}\n weight=\"regular\"\n >\n {message}\n </Text>\n {error && (\n <Box marginTop={2}>\n <Code size={1} language=\"text\">\n {error.message}\n </Code>\n {error.stack && (\n <Box marginTop={2}>\n <details>\n <summary>\n <Text size={1} muted>\n Stack trace\n </Text>\n </summary>\n <Box marginTop={2}>\n <Code size={0} language=\"text\">\n {error.stack}\n </Code>\n </Box>\n </details>\n </Box>\n )}\n </Box>\n )}\n </Stack>\n </Card>\n\n <Stack space={2}>\n {showRetry && onRetry && (\n <Button\n ref={primaryButtonRef}\n text={retryText}\n tone=\"critical\"\n onClick={onRetry}\n mode=\"default\"\n aria-label={`${retryText} action`}\n />\n )}\n <Button\n ref={!showRetry ? primaryButtonRef : undefined}\n text=\"Close\"\n tone=\"default\"\n onClick={onClose}\n mode={showRetry ? 'ghost' : 'default'}\n aria-label=\"Close error dialog\"\n />\n </Stack>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","/**\n * LocaleSelectionDialog Component\n * Requirements: 2.1, 2.2, 2.3, 2.4, 2.6, 2.7\n * \n * A dialog for selecting target locales for translation with search and validation\n */\n\nimport React, { useState, useEffect, useRef, useMemo } from 'react';\nimport { Dialog, Box, Stack, Text, Button, Card, Checkbox, TextInput, Flex, Radio } from '@sanity/ui';\nimport { SearchIcon } from '@sanity/icons';\nimport type { LocaleDefinition } from '../../types/locale';\nimport type { CollisionResolutionMode, ExistingDocumentHandling } from '../../types/pluginConfig';\n\n/**\n * Result returned when user confirms locale selection\n */\nexport interface LocaleSelectionResult {\n /** Selected locale codes */\n locales: string[];\n /** Document creation mode */\n creationMode?: 'draft' | 'published';\n /** Collision resolution mode (if override is enabled) */\n collisionResolutionMode?: CollisionResolutionMode;\n /** Existing document handling (if override is enabled) */\n existingDocumentHandling?: ExistingDocumentHandling;\n}\n\nexport interface LocaleSelectionDialogProps {\n /** Whether the dialog is open */\n open: boolean;\n /** Dialog title */\n title: string;\n /** Dialog message/description */\n message: string;\n /** Available locales to choose from */\n availableLocales: LocaleDefinition[];\n /** Currently selected locale codes */\n selectedLocales: string[];\n /** Documents being translated (for context display) */\n selectedDocuments?: any[];\n /** Translation mode */\n mode: 'single' | 'bulk';\n /** Whether multiple locales can be selected */\n allowMultiple?: boolean;\n /** Whether locale selection is required */\n required?: boolean;\n /** Whether to show creation mode option in the dialog */\n showCreationModeOption?: boolean;\n /** Default creation mode to pre-select */\n defaultCreationMode?: 'draft' | 'published';\n /** Whether to show collision resolution override options */\n showCollisionResolutionOverride?: boolean;\n /** Default collision resolution mode from config */\n defaultCollisionResolutionMode?: CollisionResolutionMode;\n /** Default existing document handling from config */\n defaultExistingDocumentHandling?: ExistingDocumentHandling;\n /** Callback when user confirms selection */\n onConfirm: (selectedLocales: string[], creationMode?: 'draft' | 'published') => void;\n /** Enhanced callback with full result object */\n onConfirmWithOptions?: (result: LocaleSelectionResult) => void;\n /** Callback when user cancels */\n onCancel: () => void;\n}\n\n/**\n * LocaleSelectionDialog component with search and multi-select functionality\n */\nexport const LocaleSelectionDialog: React.FC<LocaleSelectionDialogProps> = ({\n open,\n title,\n message,\n availableLocales,\n selectedLocales: initialSelectedLocales,\n selectedDocuments = [],\n mode,\n allowMultiple = true,\n required = true,\n showCreationModeOption = false,\n defaultCreationMode = 'draft',\n showCollisionResolutionOverride = false,\n defaultCollisionResolutionMode = 'replace',\n defaultExistingDocumentHandling = 'draft',\n onConfirm,\n onConfirmWithOptions,\n onCancel,\n}) => {\n const [selectedLocales, setSelectedLocales] = useState<Set<string>>(\n new Set(initialSelectedLocales)\n );\n const [creationMode, setCreationMode] = useState<'draft' | 'published'>(defaultCreationMode);\n const [searchQuery, setSearchQuery] = useState('');\n const [validationError, setValidationError] = useState<string | null>(null);\n const searchInputRef = useRef<HTMLInputElement>(null);\n const confirmButtonRef = useRef<HTMLButtonElement>(null);\n \n // Collision resolution state\n const [useOverrideCollision, setUseOverrideCollision] = useState(false);\n const [collisionResolutionMode, setCollisionResolutionMode] = useState<CollisionResolutionMode>(defaultCollisionResolutionMode);\n const [existingDocumentHandling, setExistingDocumentHandling] = useState<ExistingDocumentHandling>(defaultExistingDocumentHandling);\n\n // Reset state when dialog opens\n useEffect(() => {\n if (open) {\n setSelectedLocales(new Set(initialSelectedLocales));\n setCreationMode(defaultCreationMode);\n setSearchQuery('');\n setValidationError(null);\n setUseOverrideCollision(false);\n setCollisionResolutionMode(defaultCollisionResolutionMode);\n setExistingDocumentHandling(defaultExistingDocumentHandling);\n \n // Focus search input when dialog opens\n setTimeout(() => {\n searchInputRef.current?.focus();\n }, 100);\n }\n }, [open, initialSelectedLocales, defaultCreationMode, defaultCollisionResolutionMode, defaultExistingDocumentHandling]);\n\n // Filter locales based on search query\n const filteredLocales = useMemo(() => {\n if (!searchQuery.trim()) {\n return availableLocales.filter(locale => locale.enabled);\n }\n\n const query = searchQuery.toLowerCase();\n return availableLocales\n .filter(locale => locale.enabled)\n .filter(locale => \n locale.code.toLowerCase().includes(query) ||\n locale.displayName.toLowerCase().includes(query)\n );\n }, [availableLocales, searchQuery]);\n\n // Handle locale selection toggle\n const handleLocaleToggle = (localeCode: string) => {\n setValidationError(null);\n \n const newSelected = new Set(selectedLocales);\n \n if (newSelected.has(localeCode)) {\n newSelected.delete(localeCode);\n } else {\n if (!allowMultiple) {\n // Single selection mode - clear others\n newSelected.clear();\n }\n newSelected.add(localeCode);\n }\n \n setSelectedLocales(newSelected);\n };\n\n // Handle select all\n const handleSelectAll = () => {\n setValidationError(null);\n const allFilteredCodes = new Set(filteredLocales.map(locale => locale.code));\n setSelectedLocales(allFilteredCodes);\n };\n\n // Handle clear all\n const handleClearAll = () => {\n setValidationError(null);\n setSelectedLocales(new Set());\n };\n\n // Validate and confirm selection\n const handleConfirm = () => {\n // Validate selection\n if (required && selectedLocales.size === 0) {\n setValidationError('Please select at least one locale');\n return;\n }\n\n const selectedLocaleArray = Array.from(selectedLocales);\n const effectiveCreationMode = showCreationModeOption ? creationMode : undefined;\n\n // Use enhanced callback if provided\n if (onConfirmWithOptions) {\n const result: LocaleSelectionResult = {\n locales: selectedLocaleArray,\n creationMode: effectiveCreationMode\n };\n\n // Only include collision settings if override is enabled\n if (showCollisionResolutionOverride && useOverrideCollision) {\n result.collisionResolutionMode = collisionResolutionMode;\n result.existingDocumentHandling = existingDocumentHandling;\n }\n\n onConfirmWithOptions(result);\n } else {\n // Fallback to legacy callback\n onConfirm(selectedLocaleArray, effectiveCreationMode);\n }\n };\n\n // Handle keyboard navigation\n useEffect(() => {\n if (!open) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n onCancel();\n } else if (event.key === 'Enter' && event.ctrlKey) {\n // Ctrl+Enter to confirm\n event.preventDefault();\n handleConfirm();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [open, selectedLocales, onCancel]);\n\n if (!open) return null;\n\n const documentCount = selectedDocuments.length || 1;\n const isValid = !required || selectedLocales.size > 0;\n\n return (\n <Dialog\n id=\"locale-selection-dialog\"\n header={title}\n onClose={onCancel}\n onClickOutside={onCancel}\n width={1}\n role=\"dialog\"\n aria-labelledby=\"locale-selection-dialog-title\"\n aria-describedby=\"locale-selection-dialog-description\"\n >\n <Box padding={4}>\n <Stack space={4}>\n {/* Description */}\n <Card>\n <Box padding={3}>\n <Stack space={3}>\n <Text\n id=\"locale-selection-dialog-description\"\n size={2}\n weight=\"regular\"\n >\n {message}\n </Text>\n <Text size={1} muted>\n {mode === 'bulk' \n ? `Translating ${documentCount} document${documentCount !== 1 ? 's' : ''}`\n : 'Translating 1 document'\n }\n </Text>\n </Stack>\n </Box>\n </Card>\n\n {/* Search Input */}\n <Box>\n <TextInput\n ref={searchInputRef}\n icon={SearchIcon}\n placeholder=\"Search locales by code or name...\"\n value={searchQuery}\n onChange={(event) => setSearchQuery(event.currentTarget.value)}\n aria-label=\"Search locales\"\n />\n </Box>\n\n {/* Locale Selection List */}\n <Card border padding={3}>\n <Stack space={3}>\n {/* Selection Controls */}\n {allowMultiple && filteredLocales.length > 1 && (\n <Flex justify=\"space-between\" align=\"center\">\n <Text size={1} weight=\"semibold\">\n {selectedLocales.size} of {filteredLocales.length} selected\n </Text>\n <Flex gap={2}>\n <Button\n text=\"Select All\"\n mode=\"ghost\"\n fontSize={1}\n padding={2}\n onClick={handleSelectAll}\n disabled={selectedLocales.size === filteredLocales.length}\n />\n <Button\n text=\"Clear All\"\n mode=\"ghost\"\n fontSize={1}\n padding={2}\n onClick={handleClearAll}\n disabled={selectedLocales.size === 0}\n />\n </Flex>\n </Flex>\n )}\n\n {/* Locale List */}\n <Box style={{ maxHeight: '300px', overflowY: 'auto' }}>\n <Stack space={2}>\n {filteredLocales.length === 0 ? (\n <Box padding={3}>\n <Text size={1} muted align=\"center\">\n {searchQuery \n ? 'No locales match your search'\n : 'No locales available. Please configure locales first.'\n }\n </Text>\n </Box>\n ) : (\n filteredLocales.map((locale) => (\n <Card\n key={locale.code}\n padding={3}\n radius={2}\n shadow={1}\n style={{ cursor: 'pointer' }}\n onClick={() => handleLocaleToggle(locale.code)}\n role=\"checkbox\"\n aria-checked={selectedLocales.has(locale.code)}\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleLocaleToggle(locale.code);\n }\n }}\n >\n <Flex align=\"center\" gap={3}>\n <Checkbox\n checked={selectedLocales.has(locale.code)}\n readOnly\n aria-label={`Select ${locale.displayName}`}\n />\n <Stack space={1} flex={1}>\n <Text size={2} weight=\"medium\">\n {locale.displayName}\n </Text>\n <Text size={1} muted>\n {locale.code}\n </Text>\n </Stack>\n </Flex>\n </Card>\n ))\n )}\n </Stack>\n </Box>\n </Stack>\n </Card>\n\n {/* Creation Mode Selection */}\n {showCreationModeOption && (\n <Card border padding={3}>\n <Stack space={3}>\n <Text size={1} weight=\"semibold\">\n Document Creation Mode\n </Text>\n <Text size={1} muted>\n Choose whether to create translated documents as drafts or publish them immediately.\n </Text>\n <Stack space={2}>\n <Card\n padding={3}\n radius={2}\n tone={creationMode === 'draft' ? 'primary' : 'default'}\n style={{ cursor: 'pointer' }}\n onClick={() => setCreationMode('draft')}\n >\n <Flex align=\"center\" gap={3}>\n <Radio\n checked={creationMode === 'draft'}\n readOnly\n aria-label=\"Create as draft\"\n />\n <Stack space={1} flex={1}>\n <Text size={2} weight=\"medium\">\n Draft\n </Text>\n <Text size={1} muted>\n Create documents as drafts that need to be published manually\n </Text>\n </Stack>\n </Flex>\n </Card>\n <Card\n padding={3}\n radius={2}\n tone={creationMode === 'published' ? 'primary' : 'default'}\n style={{ cursor: 'pointer' }}\n onClick={() => setCreationMode('published')}\n >\n <Flex align=\"center\" gap={3}>\n <Radio\n checked={creationMode === 'published'}\n readOnly\n aria-label=\"Create as published\"\n />\n <Stack space={1} flex={1}>\n <Text size={2} weight=\"medium\">\n Published\n </Text>\n <Text size={1} muted>\n Create and publish documents immediately\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Stack>\n </Stack>\n </Card>\n )}\n\n {/* Collision Resolution Override */}\n {showCollisionResolutionOverride && (\n <Card border padding={3}>\n <Stack space={3}>\n <Flex align=\"center\" gap={3}>\n <Checkbox\n checked={useOverrideCollision}\n onChange={() => setUseOverrideCollision(!useOverrideCollision)}\n aria-label=\"Override collision resolution settings\"\n />\n <Text size={1} weight=\"semibold\">\n Override Collision Handling\n </Text>\n </Flex>\n <Text size={1} muted>\n {useOverrideCollision \n ? 'Configure how to handle existing translations for this operation.'\n : `Using default: ${defaultCollisionResolutionMode === 'replace' ? 'Replace existing' : 'Create new'}`\n }\n </Text>\n\n {useOverrideCollision && (\n <Stack space={3}>\n {/* Collision Resolution Mode Selection */}\n <Stack space={2}>\n <Text size={1} weight=\"medium\">\n When a translation already exists:\n </Text>\n <Card\n padding={3}\n radius={2}\n tone={collisionResolutionMode === 'replace' ? 'primary' : 'default'}\n style={{ cursor: 'pointer' }}\n onClick={() => setCollisionResolutionMode('replace')}\n >\n <Flex align=\"center\" gap={3}>\n <Radio\n checked={collisionResolutionMode === 'replace'}\n readOnly\n aria-label=\"Replace existing translation\"\n />\n <Stack space={1} flex={1}>\n <Text size={2} weight=\"medium\">\n Replace Existing\n </Text>\n <Text size={1} muted>\n Overwrite the existing translated document with new content\n </Text>\n </Stack>\n </Flex>\n </Card>\n <Card\n padding={3}\n radius={2}\n tone={collisionResolutionMode === 'create' ? 'primary' : 'default'}\n style={{ cursor: 'pointer' }}\n onClick={() => setCollisionResolutionMode('create')}\n >\n <Flex align=\"center\" gap={3}>\n <Radio\n checked={collisionResolutionMode === 'create'}\n readOnly\n aria-label=\"Create new translation\"\n />\n <Stack space={1} flex={1}>\n <Text size={2} weight=\"medium\">\n Create New\n </Text>\n <Text size={1} muted>\n Create a new translated document alongside the existing one\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Stack>\n\n {/* Existing Document Handling (only when Create mode is selected) */}\n {collisionResolutionMode === 'create' && (\n <Stack space={2}>\n <Text size={1} weight=\"medium\">\n Handle existing document:\n </Text>\n <Card\n padding={3}\n radius={2}\n tone={existingDocumentHandling === 'draft' ? 'primary' : 'default'}\n style={{ cursor: 'pointer' }}\n onClick={() => setExistingDocumentHandling('draft')}\n >\n <Flex align=\"center\" gap={3}>\n <Radio\n checked={existingDocumentHandling === 'draft'}\n readOnly\n aria-label=\"Set existing to draft\"\n />\n <Stack space={1} flex={1}>\n <Text size={2} weight=\"medium\">\n Set to Draft\n </Text>\n <Text size={1} muted>\n Convert the existing document to a draft (unpublish)\n </Text>\n </Stack>\n </Flex>\n </Card>\n <Card\n padding={3}\n radius={2}\n tone={existingDocumentHandling === 'delete' ? 'caution' : 'default'}\n style={{ cursor: 'pointer' }}\n onClick={() => setExistingDocumentHandling('delete')}\n >\n <Flex align=\"center\" gap={3}>\n <Radio\n checked={existingDocumentHandling === 'delete'}\n readOnly\n aria-label=\"Delete existing document\"\n />\n <Stack space={1} flex={1}>\n <Text size={2} weight=\"medium\">\n Delete\n </Text>\n <Text size={1} muted>\n Permanently delete the existing translated document\n </Text>\n </Stack>\n </Flex>\n </Card>\n </Stack>\n )}\n </Stack>\n )}\n </Stack>\n </Card>\n )}\n\n {/* Validation Error */}\n {validationError && (\n <Card tone=\"critical\" padding={3}>\n <Text size={1} style={{ color: 'var(--card-fg-color)' }}>\n {validationError}\n </Text>\n </Card>\n )}\n\n {/* Action Buttons */}\n <Stack space={2}>\n <Button\n ref={confirmButtonRef}\n text={`Translate to ${selectedLocales.size} locale${selectedLocales.size !== 1 ? 's' : ''}`}\n tone=\"primary\"\n onClick={handleConfirm}\n disabled={!isValid || filteredLocales.length === 0}\n mode=\"default\"\n aria-label=\"Confirm locale selection and start translation\"\n />\n <Button\n text=\"Cancel\"\n tone=\"default\"\n onClick={onCancel}\n mode=\"ghost\"\n aria-label=\"Cancel locale selection\"\n />\n </Stack>\n\n {/* Keyboard Hint */}\n <Text size={1} muted align=\"center\">\n Press Ctrl+Enter to confirm, Esc to cancel\n </Text>\n </Stack>\n </Box>\n </Dialog>\n );\n};\n","/**\n * Dialog management service with React state management\n * Requirements: 3.1, 3.2, 3.5, 3.6, 3.7\n * \n * Centralized dialog management with queue support for multiple simultaneous dialogs\n */\n\nimport React, { createContext, useContext, useState, useCallback, ReactNode } from 'react';\nimport type {\n DialogManager,\n ConfirmationDialogOptions,\n SuccessDialogOptions,\n ErrorDialogOptions,\n LocaleSelectionDialogOptions,\n LocaleSelectionResult,\n} from '../types/dialog';\nimport { ConfirmationDialog } from '../components/dialogs/ConfirmationDialog';\nimport { SuccessDialog } from '../components/dialogs/SuccessDialog';\nimport { ErrorDialog } from '../components/dialogs/ErrorDialog';\nimport { LocaleSelectionDialog } from '../components/dialogs/LocaleSelectionDialog';\n\n/**\n * Dialog types for queue management\n */\ntype DialogType = 'confirmation' | 'success' | 'error' | 'localeSelection';\n\n/**\n * Dialog options union type\n */\ntype DialogOptions =\n | ConfirmationDialogOptions\n | SuccessDialogOptions\n | ErrorDialogOptions\n | LocaleSelectionDialogOptions;\n\n/**\n * Dialog queue item structure\n */\ninterface DialogQueueItem {\n id: string;\n type: DialogType;\n options: DialogOptions;\n resolve?: (value: unknown) => void;\n reject?: (error: Error) => void;\n}\n\n/**\n * Dialog context state\n */\ninterface DialogContextState {\n currentDialog: DialogQueueItem | null;\n dialogQueue: DialogQueueItem[];\n showConfirmation: (options: ConfirmationDialogOptions) => Promise<boolean>;\n showLocaleSelection: (options: LocaleSelectionDialogOptions) => Promise<LocaleSelectionResult>;\n showSuccess: (options: SuccessDialogOptions) => void;\n showError: (options: ErrorDialogOptions) => Promise<boolean>;\n closeAll: () => void;\n}\n\n/**\n * Dialog context for React components\n */\nconst DialogContext = createContext<DialogContextState | null>(null);\n\n/**\n * Hook to access dialog service from React components\n */\nexport const useDialogService = (): DialogContextState => {\n const context = useContext(DialogContext);\n if (!context) {\n throw new Error('useDialogService must be used within a DialogProvider');\n }\n return context;\n};\n\n/**\n * Dialog Provider Props\n */\ninterface DialogProviderProps {\n children: ReactNode;\n}\n\n/**\n * Dialog Provider Component\n * Manages dialog state and queue for the entire application\n */\nexport const DialogProvider: React.FC<DialogProviderProps> = ({ children }) => {\n const [currentDialog, setCurrentDialog] = useState<DialogQueueItem | null>(null);\n const [dialogQueue, setDialogQueue] = useState<DialogQueueItem[]>([]);\n\n /**\n * Process the next dialog in the queue\n */\n const processNextDialog = useCallback(() => {\n setDialogQueue((queue) => {\n if (queue.length === 0) {\n setCurrentDialog(null);\n return queue;\n }\n const [next, ...rest] = queue;\n setCurrentDialog(next);\n return rest;\n });\n }, []);\n\n /**\n * Add a dialog to the queue\n */\n const enqueueDialog = useCallback(\n <T,>(type: DialogType, options: DialogOptions): Promise<T> => {\n return new Promise((resolve, reject) => {\n const dialogItem: DialogQueueItem = {\n id: `dialog-${Date.now()}-${Math.random()}`,\n type,\n options,\n resolve: resolve as (value: unknown) => void,\n reject,\n };\n\n setDialogQueue((queue) => {\n // If no current dialog, show immediately\n if (!currentDialog && queue.length === 0) {\n setCurrentDialog(dialogItem);\n return [];\n }\n // Otherwise add to queue\n return [...queue, dialogItem];\n });\n });\n },\n [currentDialog]\n );\n\n /**\n * Close the current dialog and process next in queue\n */\n const closeCurrentDialog = useCallback(\n (result?: unknown) => {\n if (currentDialog?.resolve) {\n currentDialog.resolve(result);\n }\n processNextDialog();\n },\n [currentDialog, processNextDialog]\n );\n\n /**\n * Show a confirmation dialog\n */\n const showConfirmation = useCallback(\n (options: ConfirmationDialogOptions): Promise<boolean> => {\n return enqueueDialog('confirmation', options);\n },\n [enqueueDialog]\n );\n\n /**\n * Show a locale selection dialog\n */\n const showLocaleSelection = useCallback(\n (options: LocaleSelectionDialogOptions): Promise<LocaleSelectionResult> => {\n return enqueueDialog('localeSelection', options);\n },\n [enqueueDialog]\n );\n\n /**\n * Show a success dialog (non-blocking)\n */\n const showSuccess = useCallback(\n (options: SuccessDialogOptions): void => {\n enqueueDialog('success', options).catch(() => {\n // Success dialogs don't reject\n });\n },\n [enqueueDialog]\n );\n\n /**\n * Show an error dialog\n */\n const showError = useCallback(\n (options: ErrorDialogOptions): Promise<boolean> => {\n return enqueueDialog('error', options);\n },\n [enqueueDialog]\n );\n\n /**\n * Close all dialogs and clear the queue\n */\n const closeAll = useCallback(() => {\n // Reject all pending dialogs\n if (currentDialog?.reject) {\n currentDialog.reject(new Error('Dialog closed'));\n }\n dialogQueue.forEach((dialog) => {\n if (dialog.reject) {\n dialog.reject(new Error('Dialog closed'));\n }\n });\n\n setCurrentDialog(null);\n setDialogQueue([]);\n }, [currentDialog, dialogQueue]);\n\n /**\n * Handle confirmation dialog actions\n */\n const handleConfirmationConfirm = useCallback(() => {\n closeCurrentDialog(true);\n }, [closeCurrentDialog]);\n\n const handleConfirmationCancel = useCallback(() => {\n closeCurrentDialog(false);\n }, [closeCurrentDialog]);\n\n /**\n * Handle locale selection dialog actions\n */\n const handleLocaleSelectionConfirm = useCallback(\n (selectedLocales: string[], creationMode?: 'draft' | 'published') => {\n // Convert to LocaleSelectionResult (basic callback)\n const result: LocaleSelectionResult = {\n locales: selectedLocales,\n creationMode\n };\n closeCurrentDialog(result);\n },\n [closeCurrentDialog]\n );\n\n /**\n * Handle locale selection dialog with full options (enhanced callback)\n */\n const handleLocaleSelectionConfirmWithOptions = useCallback(\n (result: LocaleSelectionResult) => {\n closeCurrentDialog(result);\n },\n [closeCurrentDialog]\n );\n\n const handleLocaleSelectionCancel = useCallback(() => {\n closeCurrentDialog({ locales: [] });\n }, [closeCurrentDialog]);\n\n /**\n * Handle success dialog close\n */\n const handleSuccessClose = useCallback(() => {\n closeCurrentDialog(true);\n }, [closeCurrentDialog]);\n\n /**\n * Handle error dialog actions\n */\n const handleErrorClose = useCallback(() => {\n closeCurrentDialog(false);\n }, [closeCurrentDialog]);\n\n const handleErrorRetry = useCallback(() => {\n closeCurrentDialog(true);\n }, [closeCurrentDialog]);\n\n const contextValue: DialogContextState = {\n currentDialog,\n dialogQueue,\n showConfirmation,\n showLocaleSelection,\n showSuccess,\n showError,\n closeAll,\n };\n\n return (\n <DialogContext.Provider value={contextValue}>\n {children}\n\n {/* Render current dialog based on type */}\n {currentDialog?.type === 'confirmation' && (\n <ConfirmationDialog\n open={true}\n {...currentDialog.options}\n onConfirm={handleConfirmationConfirm}\n onCancel={handleConfirmationCancel}\n />\n )}\n\n {currentDialog?.type === 'localeSelection' && (\n <LocaleSelectionDialog\n open={true}\n {...(currentDialog.options as LocaleSelectionDialogOptions)}\n onConfirm={handleLocaleSelectionConfirm}\n onConfirmWithOptions={handleLocaleSelectionConfirmWithOptions}\n onCancel={handleLocaleSelectionCancel}\n />\n )}\n\n {currentDialog?.type === 'success' && (\n <SuccessDialog\n open={true}\n {...currentDialog.options}\n onClose={handleSuccessClose}\n />\n )}\n\n {currentDialog?.type === 'error' && (\n <ErrorDialog\n open={true}\n {...(currentDialog.options as ErrorDialogOptions)}\n onClose={handleErrorClose}\n onRetry={\n (currentDialog.options as ErrorDialogOptions).showRetry ? handleErrorRetry : undefined\n }\n />\n )}\n </DialogContext.Provider>\n );\n};\n\n/**\n * Singleton DialogService class for non-React contexts\n * Note: This requires the DialogProvider to be mounted in the React tree\n */\nexport class DialogService implements DialogManager {\n private static instance: DialogService;\n private contextRef: DialogContextState | null = null;\n\n private constructor() {}\n\n /**\n * Get singleton instance\n */\n public static getInstance(): DialogService {\n if (!DialogService.instance) {\n DialogService.instance = new DialogService();\n }\n return DialogService.instance;\n }\n\n /**\n * Set the context reference (called by DialogProvider)\n */\n public setContext(context: DialogContextState): void {\n this.contextRef = context;\n }\n\n /**\n * Show a confirmation dialog\n */\n public async showConfirmation(\n options: ConfirmationDialogOptions\n ): Promise<boolean> {\n if (!this.contextRef) {\n throw new Error('DialogService not initialized. Ensure DialogProvider is mounted.');\n }\n return this.contextRef.showConfirmation(options);\n }\n\n /**\n * Show a locale selection dialog\n */\n public async showLocaleSelection(\n options: LocaleSelectionDialogOptions\n ): Promise<LocaleSelectionResult> {\n if (!this.contextRef) {\n throw new Error('DialogService not initialized. Ensure DialogProvider is mounted.');\n }\n return this.contextRef.showLocaleSelection(options);\n }\n\n /**\n * Show a success notification\n */\n public showSuccess(options: SuccessDialogOptions): void {\n if (!this.contextRef) {\n throw new Error('DialogService not initialized. Ensure DialogProvider is mounted.');\n }\n this.contextRef.showSuccess(options);\n }\n\n /**\n * Show an error dialog\n */\n public async showError(options: ErrorDialogOptions): Promise<boolean> {\n if (!this.contextRef) {\n throw new Error('DialogService not initialized. Ensure DialogProvider is mounted.');\n }\n return this.contextRef.showError(options);\n }\n\n /**\n * Close all open dialogs\n */\n public closeAll(): void {\n if (!this.contextRef) {\n throw new Error('DialogService not initialized. Ensure DialogProvider is mounted.');\n }\n this.contextRef.closeAll();\n }\n}\n\n/**\n * Export singleton instance for convenience\n */\nexport const dialogService = DialogService.getInstance();\n","/**\n * Easyling Authentication Type Definitions\n * \n * This file contains all TypeScript interfaces, types, and enums\n * for Easyling authentication implementation in the Sanity Translation Plugin.\n */\n\n/**\n * Easyling configuration for connecting to the translation service\n */\nexport interface OAuthConfig {\n /** Project ID for the Easyling project */\n projectId: string;\n \n /** Long-lived access token provided by Easyling */\n accessToken: string;\n}\n\n/**\n * Result of the authentication process\n */\nexport interface AuthenticationResult {\n /** Whether authentication was successful */\n success: boolean;\n \n /** Access token if authentication succeeded */\n accessToken?: string;\n \n /** Selected project ID if authentication succeeded */\n projectId?: string;\n \n /** Error message if authentication failed */\n error?: string;\n}\n\n/**\n * Stored authentication data persisted in storage\n */\nexport interface StoredAuthData {\n /** Access token for API requests */\n accessToken: string;\n \n /** Selected project ID */\n projectId: string;\n \n /** Optional project name for display purposes */\n projectName?: string;\n \n /** Timestamp when data was stored (Unix timestamp in milliseconds) */\n storedAt: number;\n}\n\n/**\n * Authentication state enumeration\n */\nexport type AuthState = \n | 'unauthenticated' // User is not authenticated\n | 'authenticated' // User is authenticated with valid token\n | 'error'; // Authentication error occurred\n\n/**\n * Authentication state data with additional context\n */\nexport interface AuthStateData {\n /** Current authentication state */\n state: AuthState;\n \n /** Selected project ID if authenticated */\n projectId?: string;\n \n /** Project name for display if available */\n projectName?: string;\n \n /** Error message if state is 'error' */\n error?: string;\n}\n\n/**\n * Authentication error types for categorizing failures\n */\nexport enum OAuthErrorType {\n /** Invalid configuration */\n INVALID_CONFIG = 'invalid_config',\n \n /** Network error during API request */\n NETWORK_ERROR = 'network_error',\n \n /** Authentication failed */\n AUTH_FAILED = 'auth_failed',\n \n /** Storage operation failed */\n STORAGE_ERROR = 'storage_error'\n}\n\n/**\n * Custom error class for OAuth-related errors\n */\nexport class OAuthError extends Error {\n /** Error type for categorization */\n public readonly type: OAuthErrorType;\n \n /** Additional error details */\n public readonly details?: unknown;\n \n constructor(type: OAuthErrorType, message: string, details?: unknown) {\n super(message);\n this.name = 'OAuthError';\n this.type = type;\n this.details = details;\n \n // Maintains proper stack trace for where error was thrown (V8 only)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, OAuthError);\n }\n }\n\n /**\n * Get a user-friendly error message based on error type\n */\n getUserMessage(): string {\n switch (this.type) {\n case OAuthErrorType.INVALID_CONFIG:\n return 'Configuration is invalid. Please check your access token and project ID.';\n case OAuthErrorType.NETWORK_ERROR:\n return 'Network error. Please check your connection.';\n case OAuthErrorType.AUTH_FAILED:\n return 'Authentication failed. Please check your access token.';\n case OAuthErrorType.STORAGE_ERROR:\n return 'Failed to save authentication data. Please try again.';\n default:\n return 'An unexpected error occurred. Please try again.';\n }\n }\n\n /**\n * Check if this error is recoverable (user can retry)\n */\n isRecoverable(): boolean {\n return [\n OAuthErrorType.NETWORK_ERROR,\n OAuthErrorType.STORAGE_ERROR\n ].includes(this.type);\n }\n}\n","/**\n * Easyling Authentication Service\n * \n * Manages Easyling authentication configuration for the Sanity Translation Plugin.\n * Handles validation and storage of access tokens and project IDs.\n */\n\nimport {\n OAuthConfig,\n OAuthError,\n OAuthErrorType\n} from '../types/oauth';\n\n/**\n * Easyling Authentication Service\n * \n * Provides methods for managing Easyling authentication configuration.\n */\nexport class OAuthService {\n private config: OAuthConfig;\n\n /**\n * Create a new Easyling Authentication Service instance\n * \n * @param config - Easyling configuration (access token and project ID)\n * @throws {OAuthError} If configuration is invalid\n */\n constructor(config: OAuthConfig) {\n this.validateConfig(config);\n this.config = config;\n \n console.log('Easyling Authentication Service initialized', {\n projectId: config.projectId,\n hasAccessToken: !!config.accessToken\n });\n }\n\n /**\n * Validate configuration\n * \n * @param config - Configuration to validate\n * @throws {OAuthError} If configuration is invalid\n */\n private validateConfig(config: OAuthConfig): void {\n const errors: string[] = [];\n\n if (!config.accessToken || config.accessToken.trim() === '') {\n errors.push('accessToken is required');\n }\n\n if (!config.projectId || config.projectId.trim() === '') {\n errors.push('projectId is required');\n }\n\n if (errors.length > 0) {\n throw new OAuthError(\n OAuthErrorType.INVALID_CONFIG,\n `Invalid configuration: ${errors.join(', ')}`\n );\n }\n }\n\n /**\n * Get the access token\n * \n * @returns The configured access token\n */\n getAccessToken(): string {\n return this.config.accessToken;\n }\n\n /**\n * Get the project ID\n * \n * @returns The configured project ID\n */\n getProjectId(): string {\n return this.config.projectId;\n }\n\n /**\n * Get the complete configuration\n * \n * @returns The complete OAuth configuration\n */\n getConfig(): OAuthConfig {\n return { ...this.config };\n }\n}\n","/**\n * Token Storage Service\n * \n * Manages secure storage and retrieval of OAuth authentication tokens\n * and related data using Sanity Studio's localStorage wrapper.\n * \n * Requirements: 3.3, 3.4, 3.5, 6.1, 6.4, 8.4\n */\n\nimport { StoredAuthData, OAuthError, OAuthErrorType } from '../types/oauth';\n\n/**\n * Storage key for authentication data in localStorage\n */\nconst AUTH_DATA_STORAGE_KEY = 'sanity-translation-plugin:oauth:auth-data';\n\n/**\n * Token Storage Service\n * \n * Provides methods for persisting, retrieving, and managing OAuth authentication data.\n * Uses Sanity Studio's localStorage for persistence with JSON serialization.\n */\nexport class TokenStorage {\n /**\n * Store authentication data securely\n * \n * @param data - Authentication data to store\n * @throws {OAuthError} If storage operation fails\n */\n async storeAuthData(data: StoredAuthData): Promise<void> {\n try {\n // Validate required fields\n if (!data.accessToken || !data.projectId) {\n throw new OAuthError(\n OAuthErrorType.STORAGE_ERROR,\n 'Invalid auth data: missing required fields (accessToken or projectId)'\n );\n }\n\n // Add storage timestamp\n const dataToStore: StoredAuthData = {\n ...data,\n storedAt: Date.now()\n };\n\n // Serialize and store\n const serialized = JSON.stringify(dataToStore);\n localStorage.setItem(AUTH_DATA_STORAGE_KEY, serialized);\n\n console.log('Auth data stored successfully', {\n projectId: data.projectId\n });\n } catch (error) {\n // If it's already an OAuthError, rethrow it\n if (error instanceof OAuthError) {\n throw error;\n }\n\n // Wrap other errors\n throw new OAuthError(\n OAuthErrorType.STORAGE_ERROR,\n 'Failed to store authentication data',\n error\n );\n }\n }\n\n /**\n * Retrieve stored authentication data\n * \n * @returns Stored authentication data or null if not found\n * @throws {OAuthError} If storage read fails or data is corrupted\n */\n async getAuthData(): Promise<StoredAuthData | null> {\n try {\n const serialized = localStorage.getItem(AUTH_DATA_STORAGE_KEY);\n\n if (!serialized) {\n return null;\n }\n\n // Deserialize\n const data = JSON.parse(serialized) as StoredAuthData;\n\n // Validate structure\n if (!data.accessToken || !data.projectId) {\n console.warn('Stored auth data is corrupted, clearing storage');\n await this.clearAuthData();\n return null;\n }\n\n return data;\n } catch (error) {\n // Handle JSON parse errors\n if (error instanceof SyntaxError) {\n console.warn('Failed to parse stored auth data, clearing storage');\n await this.clearAuthData();\n return null;\n }\n\n throw new OAuthError(\n OAuthErrorType.STORAGE_ERROR,\n 'Failed to retrieve authentication data',\n error\n );\n }\n }\n\n /**\n * Clear all stored authentication data\n * \n * Requirements: 6.4\n * \n * @throws {OAuthError} If storage clear operation fails\n */\n async clearAuthData(): Promise<void> {\n try {\n localStorage.removeItem(AUTH_DATA_STORAGE_KEY);\n console.log('Auth data cleared successfully');\n } catch (error) {\n throw new OAuthError(\n OAuthErrorType.STORAGE_ERROR,\n 'Failed to clear authentication data',\n error\n );\n }\n }\n\n /**\n * Check if the stored token is expired\n * \n * For long-lived tokens, this always returns false if a token exists.\n * \n * @returns True if token is not found, false if token exists\n */\n async isTokenExpired(): Promise<boolean> {\n try {\n const data = await this.getAuthData();\n // Long-lived tokens don't expire, so just check if data exists\n return !data;\n } catch (error) {\n console.error('Error checking token:', error);\n // If we can't check, assume expired for safety\n return true;\n }\n }\n\n /**\n * Get a valid access token if available\n * \n * @returns Valid access token or null if not found\n */\n async getValidAccessToken(): Promise<string | null> {\n try {\n const data = await this.getAuthData();\n\n if (!data) {\n return null;\n }\n\n return data.accessToken;\n } catch (error) {\n console.error('Error getting valid access token:', error);\n return null;\n }\n }\n}\n","/**\n * Authentication State Manager\n * \n * Manages the overall authentication state and provides reactive updates\n * to UI components through an observable pattern.\n * \n * Requirements: 6.1, 6.2, 6.3, 6.4, 6.5\n */\n\nimport { AuthState, AuthStateData, OAuthError, OAuthErrorType } from '../types/oauth';\nimport { TokenStorage } from './tokenStorage';\n\n/**\n * Callback function type for state change subscriptions\n */\ntype StateChangeCallback = (state: AuthStateData) => void;\n\n/**\n * Valid state transitions to prevent invalid state changes\n */\nconst VALID_TRANSITIONS: Record<AuthState, AuthState[]> = {\n unauthenticated: ['authenticated', 'error'],\n authenticated: ['unauthenticated', 'error'],\n error: ['unauthenticated', 'authenticated']\n};\n\n/**\n * Authentication State Manager\n * \n * Provides centralized management of authentication state with reactive updates.\n * Uses observable pattern to notify subscribers of state changes.\n */\nexport class AuthStateManager {\n private currentState: AuthStateData;\n private subscribers: Set<StateChangeCallback>;\n private tokenStorage: TokenStorage;\n\n /**\n * Create a new Authentication State Manager\n * \n * Requirements: 6.1, 6.2\n * \n * @param tokenStorage - Token storage service for persistence\n */\n constructor(tokenStorage: TokenStorage) {\n this.tokenStorage = tokenStorage;\n this.subscribers = new Set();\n \n // Initialize with unauthenticated state\n this.currentState = {\n state: 'unauthenticated'\n };\n\n console.log('AuthStateManager initialized');\n }\n\n /**\n * Validate state transition\n * \n * Requirements: 6.5\n * \n * @param fromState - Current state\n * @param toState - Target state\n * @returns True if transition is valid\n */\n private isValidTransition(fromState: AuthState, toState: AuthState): boolean {\n // Allow staying in the same state\n if (fromState === toState) {\n return true;\n }\n\n const validNextStates = VALID_TRANSITIONS[fromState];\n return validNextStates.includes(toState);\n }\n\n /**\n * Get current authentication state\n * \n * Requirements: 6.1, 6.2\n * \n * @returns Current authentication state data\n */\n getState(): AuthStateData {\n return { ...this.currentState };\n }\n\n /**\n * Update authentication state and notify subscribers\n * \n * Requirements: 6.2, 6.5\n * \n * @param state - New authentication state\n * @param data - Additional state data\n * @throws {OAuthError} If state transition is invalid\n */\n setState(state: AuthState, data?: Partial<AuthStateData>): void {\n // Validate state transition\n if (!this.isValidTransition(this.currentState.state, state)) {\n throw new OAuthError(\n OAuthErrorType.INVALID_CONFIG,\n `Invalid state transition from ${this.currentState.state} to ${state}`\n );\n }\n\n // Create new state data\n const newState: AuthStateData = {\n state,\n ...data\n };\n\n // Clear error if transitioning away from error state\n if (this.currentState.state === 'error' && state !== 'error') {\n delete newState.error;\n }\n\n // Clear user data if transitioning to unauthenticated\n if (state === 'unauthenticated') {\n delete newState.projectId;\n delete newState.projectName;\n delete newState.error;\n }\n\n console.log('Auth state changed', {\n from: this.currentState.state,\n to: state,\n projectId: newState.projectId\n });\n\n // Update current state\n this.currentState = newState;\n\n // Notify all subscribers\n this.notifySubscribers();\n }\n\n /**\n * Notify all subscribers of state change\n * \n * Requirements: 6.2\n */\n private notifySubscribers(): void {\n const stateCopy = this.getState();\n \n this.subscribers.forEach(callback => {\n try {\n callback(stateCopy);\n } catch (error) {\n console.error('Error in state change subscriber:', error);\n }\n });\n }\n\n /**\n * Subscribe to state changes\n * \n * Requirements: 6.2\n * \n * @param callback - Function to call when state changes\n * @returns Unsubscribe function\n */\n subscribe(callback: StateChangeCallback): () => void {\n this.subscribers.add(callback);\n\n // Immediately call callback with current state\n try {\n callback(this.getState());\n } catch (error) {\n console.error('Error in initial state callback:', error);\n }\n\n // Return unsubscribe function\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n /**\n * Initialize state from stored authentication data\n * \n * Requirements: 6.1, 6.4\n * \n * @returns Promise that resolves when initialization is complete\n */\n async initialize(): Promise<void> {\n try {\n console.log('Initializing auth state from storage');\n\n // Load stored auth data\n const authData = await this.tokenStorage.getAuthData();\n\n if (!authData) {\n console.log('No stored auth data found, remaining unauthenticated');\n this.setState('unauthenticated');\n return;\n }\n\n // Check if token exists (long-lived tokens don't expire)\n const isExpired = await this.tokenStorage.isTokenExpired();\n\n if (isExpired) {\n console.log('No valid token found');\n this.setState('unauthenticated');\n return;\n }\n\n // Token is valid, set authenticated state\n console.log('Valid token found, setting authenticated state');\n this.setState('authenticated', {\n projectId: authData.projectId,\n projectName: authData.projectName\n });\n } catch (error) {\n console.error('Error initializing auth state:', error);\n \n // Set error state\n this.setState('error', {\n error: 'Failed to initialize authentication state'\n });\n }\n }\n\n /**\n * Logout and clear all authentication data\n * \n * Requirements: 6.3, 6.4\n * \n * @returns Promise that resolves when logout is complete\n */\n async logout(): Promise<void> {\n try {\n console.log('Logging out');\n\n // Clear stored auth data\n await this.tokenStorage.clearAuthData();\n\n // Update state to unauthenticated\n this.setState('unauthenticated');\n\n console.log('Logout complete');\n } catch (error) {\n console.error('Error during logout:', error);\n \n // Still transition to unauthenticated even if storage clear fails\n this.setState('unauthenticated');\n \n throw new OAuthError(\n OAuthErrorType.STORAGE_ERROR,\n 'Failed to clear authentication data during logout',\n error\n );\n }\n }\n}\n","/**\n * OAuth Configuration Storage Adapter\n * Requirements: 9.1, 9.4\n * \n * Now delegates to UnifiedConfigStorage for centralized configuration management.\n * OAuth settings are stored in the EL_PluginConfiguration document alongside\n * locale and DNT configurations.\n */\n\nimport { SanityClient } from 'sanity';\nimport { OAuthConfig } from '../types/oauth';\nimport { UnifiedConfigStorage } from './unifiedConfigStorage';\n\n/**\n * Legacy configuration document ID (deprecated)\n * @deprecated Now uses unified configuration\n */\nconst LEGACY_OAUTH_CONFIG_DOC_ID = 'sanity-translation-plugin.oauth-config';\n\n/**\n * OAuth configuration storage adapter\n * Now uses UnifiedConfigStorage for centralized management\n * Requirements: 9.1, 9.4\n */\nexport class OAuthConfigStorage {\n private unifiedStorage: UnifiedConfigStorage;\n private client: SanityClient;\n\n constructor(client: SanityClient) {\n this.client = client;\n this.unifiedStorage = new UnifiedConfigStorage(client);\n }\n\n /**\n * Load OAuth configuration from unified storage\n * Requirements: 9.1, 9.4\n */\n async load(): Promise<OAuthConfig | null> {\n try {\n // Try loading from unified configuration first\n const config = await this.unifiedStorage.loadOAuth();\n \n if (config) {\n console.log('Loaded OAuth configuration from unified storage');\n return config;\n }\n\n // Try migrating from legacy storage\n const legacyConfig = await this.loadLegacy();\n if (legacyConfig) {\n console.log('Migrating OAuth configuration from legacy storage...');\n await this.save(legacyConfig);\n await this.deleteLegacy();\n console.log('OAuth configuration migration complete');\n return legacyConfig;\n }\n\n console.log('No OAuth configuration found');\n return null;\n } catch (error) {\n console.error('Failed to load OAuth configuration:', error);\n throw error;\n }\n }\n\n /**\n * Save OAuth configuration to unified storage\n * Requirements: 9.1, 9.4\n */\n async save(config: OAuthConfig): Promise<void> {\n try {\n await this.unifiedStorage.saveOAuth(config);\n console.log('Saved OAuth configuration to unified storage');\n } catch (error) {\n console.error('Failed to save OAuth configuration:', error);\n throw error;\n }\n }\n\n /**\n * Delete OAuth configuration\n * Only clears OAuth fields, preserves other configuration\n */\n async delete(): Promise<void> {\n try {\n await this.unifiedStorage.update({\n projectId: undefined,\n accessToken: undefined\n });\n console.log('Deleted OAuth configuration');\n } catch (error) {\n console.error('Failed to delete OAuth configuration:', error);\n throw error;\n }\n }\n\n // Legacy migration methods\n\n /**\n * Load from legacy OAuth-specific document\n * @private\n */\n private async loadLegacy(): Promise<OAuthConfig | null> {\n try {\n const doc = await this.client.fetch<OAuthConfig | null>(\n `*[_id == $id][0]`,\n { id: LEGACY_OAUTH_CONFIG_DOC_ID }\n );\n\n if (!doc) {\n return null;\n }\n\n return {\n projectId: (doc as any).projectId,\n accessToken: (doc as any).accessToken\n };\n } catch (error) {\n console.error('Failed to load legacy OAuth configuration:', error);\n return null;\n }\n }\n\n /**\n * Delete legacy OAuth document after migration\n * @private\n */\n private async deleteLegacy(): Promise<void> {\n try {\n await this.client.delete(LEGACY_OAUTH_CONFIG_DOC_ID);\n console.log('Deleted legacy OAuth configuration document');\n } catch (error) {\n console.warn('Failed to delete legacy OAuth document:', error);\n // Non-fatal - migration already succeeded\n }\n }\n}\n","/**\n * OAuth Service Manager\n * Requirements: 6.1, 10.1, 9.2\n * \n * Manages singleton instances of OAuth services and handles initialization.\n * Provides centralized access to OAuth services throughout the plugin.\n */\n\nimport { SanityClient } from 'sanity';\nimport { OAuthService } from './oauthService';\nimport { TokenStorage } from './tokenStorage';\nimport { AuthStateManager } from './authStateManager';\nimport { TranslationService, UnifiedConfigStorage } from '@easyling/sanity-connector-shared';\nimport { OAuthConfigStorage } from './oauthConfigStorage';\nimport { OAuthConfig } from '../types/oauth';\n\n/**\n * OAuth Service Manager\n * \n * Singleton manager for OAuth services. Ensures all services are properly\n * initialized and provides centralized access throughout the plugin.\n */\nexport class OAuthServiceManager {\n private static instance: OAuthServiceManager | null = null;\n \n private oauthService: OAuthService | null = null;\n private tokenStorage: TokenStorage;\n private authStateManager: AuthStateManager;\n private translationService: TranslationService;\n private oauthConfigStorage: OAuthConfigStorage;\n private unifiedConfigStorage: UnifiedConfigStorage;\n private client: SanityClient;\n private initialized: boolean = false;\n\n /**\n * Private constructor to enforce singleton pattern\n * Requirements: 6.1, 10.1\n */\n private constructor(client: SanityClient) {\n this.client = client;\n \n // Initialize core services\n this.tokenStorage = new TokenStorage();\n this.authStateManager = new AuthStateManager(this.tokenStorage);\n this.translationService = new TranslationService();\n this.oauthConfigStorage = new OAuthConfigStorage(client);\n this.unifiedConfigStorage = new UnifiedConfigStorage(client);\n \n console.log('OAuthServiceManager created');\n }\n\n /**\n * Get or create the singleton instance\n * Requirements: 6.1, 10.1\n * \n * @param client - Sanity client instance\n * @returns Singleton instance of OAuthServiceManager\n */\n static getInstance(client: SanityClient): OAuthServiceManager {\n if (!OAuthServiceManager.instance) {\n OAuthServiceManager.instance = new OAuthServiceManager(client);\n }\n return OAuthServiceManager.instance;\n }\n\n /**\n * Reset the singleton instance (useful for testing)\n */\n static resetInstance(): void {\n OAuthServiceManager.instance = null;\n }\n\n /**\n * Initialize OAuth services\n * Requirements: 6.1, 10.1\n * \n * Loads OAuth configuration, initializes OAuth service if configured,\n * initializes authentication state from storage, and sets up translation\n * service with authentication if available.\n * \n * @returns Promise that resolves when initialization is complete\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n console.log('OAuthServiceManager already initialized');\n return;\n }\n\n try {\n console.log('Initializing OAuth services...');\n\n // Set up configuration listener\n this.setupConfigListener();\n\n // Load OAuth configuration\n const oauthConfig = await this.loadOAuthConfig();\n\n if (oauthConfig) {\n // Initialize OAuth service with configuration\n this.oauthService = new OAuthService(oauthConfig);\n console.log('OAuth service initialized with configuration');\n } else {\n console.log('No OAuth configuration found, OAuth features will be disabled');\n }\n\n // Initialize authentication state from storage\n await this.authStateManager.initialize();\n console.log('Authentication state initialized');\n\n // Set up translation service with authentication if available\n await this.setupTranslationServiceAuth();\n\n this.initialized = true;\n console.log('OAuth services initialization complete');\n } catch (error) {\n console.error('Error initializing OAuth services:', error);\n // Don't throw - allow plugin to continue without OAuth\n this.initialized = true;\n }\n }\n\n /**\n * Set up listener for configuration changes\n * \n * Monitors the unified configuration document for changes and reloads\n * the configuration automatically.\n */\n private setupConfigListener(): void {\n const query = `*[_id == \"sanity-translation-plugin.config\"]`;\n this.client.listen(query).subscribe(async (update: any) => {\n console.log('Configuration updated, reloading services...');\n \n // Use the result from the update if available (most reliable source of new truth)\n // Otherwise fallback to fetching\n let oauthConfig = null;\n \n if (update.result) {\n console.log('Using updated document from listener event');\n oauthConfig = {\n projectId: update.result.projectId,\n accessToken: update.result.accessToken\n };\n } else {\n console.log('Fetching updated configuration');\n oauthConfig = await this.loadOAuthConfig();\n }\n \n if (oauthConfig && oauthConfig.accessToken && oauthConfig.projectId) {\n console.log('Applying new OAuth configuration from update');\n \n // Update OAuth service\n this.oauthService = new OAuthService(oauthConfig);\n \n // Update auth state and translation service\n // This will also update localStorage\n await this.saveAuth(oauthConfig.accessToken, oauthConfig.projectId);\n }\n \n // Refresh translation endpoint settings\n await this.setupTranslationServiceEndpoint();\n \n console.log('Services reloaded from configuration update');\n });\n }\n\n /**\n * Load OAuth configuration from storage\n * Requirements: 9.1, 9.4\n * \n * @returns OAuth configuration or null if not configured\n */\n private async loadOAuthConfig(): Promise<OAuthConfig | null> {\n try {\n return await this.oauthConfigStorage.load();\n } catch (error) {\n console.error('Failed to load OAuth configuration:', error);\n return null;\n }\n }\n\n /**\n * Set up translation service with authentication if available\n * \n * Checks for valid stored authentication and configures the translation\n * service to use it.\n * \n * Supports dual mode operation:\n * - If OAuth is configured and authenticated, sets up OAuth authentication\n * - If OAuth is not configured, translation service works in legacy mode\n * \n * IMPORTANT: This method also syncs configuration from Sanity to localStorage\n * if configuration exists in Sanity but not in localStorage (migration support).\n */\n private async setupTranslationServiceAuth(): Promise<void> {\n try {\n // Always set up the translation endpoint with fallback to default\n await this.setupTranslationServiceEndpoint();\n \n // Check Sanity configuration first (source of truth)\n // Requirements: 9.1, 9.4\n const oauthConfig = await this.loadOAuthConfig();\n\n if (oauthConfig && oauthConfig.accessToken && oauthConfig.projectId) {\n console.log('Found configuration in Sanity, syncing to localStorage');\n \n // Store in localStorage to keep in sync\n await this.tokenStorage.storeAuthData({\n accessToken: oauthConfig.accessToken,\n projectId: oauthConfig.projectId,\n storedAt: Date.now()\n });\n \n // Update auth state\n this.authStateManager.setState('authenticated', {\n projectId: oauthConfig.projectId\n });\n \n // Set authentication on translation service\n this.translationService.setAuthToken(\n oauthConfig.accessToken,\n oauthConfig.projectId\n );\n \n console.log('Translation service configured with Easyling authentication from Sanity config');\n } else {\n // Fallback to localStorage if no Sanity config (legacy/offline behavior)\n const authData = await this.tokenStorage.getAuthData();\n \n if (authData) {\n this.translationService.setAuthToken(\n authData.accessToken,\n authData.projectId\n );\n console.log('Translation service configured with Easyling authentication from localStorage');\n } else {\n console.log('No authentication data available, translation service will use legacy mode');\n }\n }\n \n // Load and set translation endpoint with fallback to default\n await this.setupTranslationServiceEndpoint();\n } catch (error) {\n console.error('Error setting up translation service authentication:', error);\n console.log('Translation service will fall back to legacy mode');\n \n // Even if auth fails, try to set the endpoint\n try {\n await this.setupTranslationServiceEndpoint();\n } catch (endpointError) {\n console.error('Error setting up translation service endpoint:', endpointError);\n }\n }\n }\n\n /**\n * Set up translation service endpoint and settings from configuration\n * \n * Loads translation endpoint, content type, and other settings from\n * unified configuration with fallback to defaults.\n */\n private async setupTranslationServiceEndpoint(): Promise<void> {\n try {\n // Load all translation settings from unified config\n const endpoint = await this.unifiedConfigStorage.getTranslationEndpoint();\n const requestContentType = await this.unifiedConfigStorage.getRequestContentType();\n const responseAcceptHeader = await this.unifiedConfigStorage.getResponseAcceptHeader();\n \n // Apply all settings to the translation service\n this.translationService.setConfiguration(\n endpoint,\n requestContentType,\n responseAcceptHeader\n );\n \n console.log(`Translation service configured:`, {\n endpoint,\n requestContentType,\n responseAcceptHeader\n });\n } catch (error) {\n console.error('Error loading translation service configuration:', error);\n // The translation service will use its default settings\n }\n }\n\n /**\n * Get OAuth service instance\n * Requirements: 1.1, 1.2, 1.3\n * \n * @returns OAuth service instance or null if not configured\n */\n getOAuthService(): OAuthService | null {\n return this.oauthService;\n }\n\n /**\n * Get token storage instance\n * Requirements: 3.3, 3.4, 3.5\n * \n * @returns Token storage instance\n */\n getTokenStorage(): TokenStorage {\n return this.tokenStorage;\n }\n\n /**\n * Get authentication state manager instance\n * Requirements: 6.1, 6.2, 6.3\n * \n * @returns Authentication state manager instance\n */\n getAuthStateManager(): AuthStateManager {\n return this.authStateManager;\n }\n\n /**\n * Get translation service instance\n * Requirements: 4.1, 4.2, 4.3\n * \n * @returns Translation service instance\n */\n getTranslationService(): TranslationService {\n return this.translationService;\n }\n\n /**\n * Get OAuth configuration storage instance\n * Requirements: 9.1, 9.4\n * \n * @returns OAuth configuration storage instance\n */\n getOAuthConfigStorage(): OAuthConfigStorage {\n return this.oauthConfigStorage;\n }\n\n /**\n * Check if OAuth is configured\n * Requirements: 10.1, 10.3\n * \n * @returns True if OAuth service is initialized\n */\n isOAuthConfigured(): boolean {\n return this.oauthService !== null;\n }\n\n /**\n * Detect which authentication method should be used\n * Requirements: 10.1, 10.3, 10.4\n * \n * Determines whether to use OAuth or legacy endpoint-based authentication\n * based on the presence of OAuth configuration.\n * \n * @returns 'oauth' if OAuth is configured, 'legacy' otherwise\n */\n getAuthenticationMode(): 'oauth' | 'legacy' {\n return this.isOAuthConfigured() ? 'oauth' : 'legacy';\n }\n\n /**\n * Check if user is authenticated with OAuth\n * Requirements: 10.1, 10.3\n * \n * @returns True if OAuth is configured and user has valid authentication\n */\n async isOAuthAuthenticated(): Promise<boolean> {\n if (!this.isOAuthConfigured()) {\n return false;\n }\n\n const authData = await this.tokenStorage.getAuthData();\n if (!authData) {\n return false;\n }\n\n const isExpired = await this.tokenStorage.isTokenExpired();\n return !isExpired;\n }\n\n /**\n * Get authentication status information\n * Requirements: 10.1, 10.3, 10.4\n * \n * Provides detailed information about the current authentication mode\n * and status for display to users.\n * \n * @returns Object with authentication mode and status details\n */\n async getAuthenticationStatus(): Promise<{\n mode: 'oauth' | 'legacy';\n isOAuthConfigured: boolean;\n isAuthenticated: boolean;\n requiresAuthentication: boolean;\n }> {\n const mode = this.getAuthenticationMode();\n const isOAuthConfigured = this.isOAuthConfigured();\n const isAuthenticated = await this.isOAuthAuthenticated();\n\n return {\n mode,\n isOAuthConfigured,\n isAuthenticated,\n // OAuth mode requires authentication, legacy mode does not\n requiresAuthentication: mode === 'oauth' && !isAuthenticated\n };\n }\n\n /**\n * Check if services are initialized\n * Requirements: 6.1\n * \n * @returns True if initialization is complete\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * Save authentication configuration and data\n * \n * Stores the access token and project ID, and configures the translation service.\n * \n * @param accessToken - The Easyling access token\n * @param projectId - The Easyling project ID\n */\n async saveAuth(accessToken: string, projectId: string): Promise<void> {\n try {\n // Store authentication data\n await this.tokenStorage.storeAuthData({\n accessToken,\n projectId,\n storedAt: Date.now()\n });\n\n // Update authentication state\n this.authStateManager.setState('authenticated', {\n projectId\n });\n\n // Set up translation service authentication\n this.translationService.setAuthToken(accessToken, projectId);\n\n console.log('Authentication saved successfully');\n } catch (error) {\n console.error('Failed to save authentication:', error);\n this.authStateManager.setState('error', {\n error: error instanceof Error ? error.message : 'Failed to save authentication'\n });\n throw error;\n }\n }\n\n /**\n * Logout and clear authentication\n */\n async logout(): Promise<void> {\n // Clear translation service authentication\n this.translationService.clearAuth();\n\n // Logout from auth state manager (clears storage)\n await this.authStateManager.logout();\n\n console.log('Logged out successfully');\n }\n\n /**\n * Refresh configuration from Sanity\n * \n * Reloads the translation service endpoint and other settings from Sanity.\n * This should be called when the configuration has been updated in Sanity\n * to ensure the plugin is using the latest settings.\n */\n async refreshConfiguration(): Promise<void> {\n try {\n console.log('Refreshing configuration from Sanity...');\n await this.setupTranslationServiceEndpoint();\n console.log('Configuration refreshed successfully');\n } catch (error) {\n console.error('Error refreshing configuration:', error);\n throw error;\n }\n }\n}\n","import { DocumentActionComponent, DocumentActionProps, DocumentActionDescription, useClient } from 'sanity';\nimport { TranslateIcon } from '@sanity/icons';\nimport { ContentExtractor } from '../services/contentExtractor';\nimport { DocumentCreationService } from '../services/documentCreationService';\nimport { UnifiedConfigStorage } from '../services/unifiedConfigStorage';\nimport { LocaleService } from '../services/localeService';\nimport { SanityLocaleStorageAdapter } from '../services/localeStorageAdapter';\nimport { useDialogService } from '../services/dialogService';\nimport { OAuthServiceManager } from '../services/oauthServiceManager';\nimport type { CollisionResolutionMode, ExistingDocumentHandling } from '../types/pluginConfig';\n\n// Simple state management for loading state\nlet isTranslating = false;\n\n/**\n * Document action for translating a single document\n * Requirements: 2.1, 2.3, 3.1, 3.3, 4.1, 4.2\n */\nexport const translateDocumentAction: DocumentActionComponent = (props: DocumentActionProps) => {\n console.log('translateDocumentAction called with props:', { id: props.id, type: props.type, hasDraft: !!props.draft, hasPublished: !!props.published });\n\n const { draft, published, id, type, onComplete } = props;\n const client = useClient({ apiVersion: '2023-01-01' });\n const dialogService = useDialogService();\n\n // Use draft if available, otherwise use published version\n const document = draft || published;\n\n // Don't show action if no document is available\n if (!document) {\n console.log(\"no document found\");\n return null;\n }\n\n // Don't show translate action for plugin configuration documents\n const pluginConfigTypes = ['EL_PluginConfiguration', 'EL_oauth-config', 'EL_translation-plugin-config'];\n if (pluginConfigTypes.includes(type)) {\n console.log('Excluding translate action for plugin configuration type:', type);\n return null;\n }\n\n console.log('translateDocumentAction returning action for document:', id);\n\n const handleTranslate = async () => {\n // Prevent multiple simultaneous translations\n if (isTranslating) {\n return;\n }\n\n isTranslating = true;\n\n try {\n // Initialize services\n const contentExtractor = new ContentExtractor();\n const documentCreationService = new DocumentCreationService(client);\n const storageAdapter = new SanityLocaleStorageAdapter(client);\n const localeService = new LocaleService(storageAdapter);\n \n // Get OAuth service manager and translation service\n // Requirements: 4.1, 4.2, 4.3, 10.5\n const serviceManager = OAuthServiceManager.getInstance(client);\n \n // Refresh configuration to ensure we have the latest endpoint and settings\n await serviceManager.refreshConfiguration();\n \n const translationService = serviceManager.getTranslationService();\n const authStateManager = serviceManager.getAuthStateManager();\n \n // Check authentication state\n const authState = authStateManager.getState();\n \n // If OAuth is configured but not authenticated, prompt user to authenticate\n if (serviceManager.isOAuthConfigured() && authState.state !== 'authenticated') {\n await dialogService.showError({\n title: 'Authentication Required',\n message: 'You need to configure your Easyling credentials to use translation services.',\n error: new Error('Please go to the Easyling Configuration tool to enter your access token and project ID.')\n });\n return;\n }\n\n // Load locale configuration\n await localeService.loadConfig();\n const enabledLocales = localeService.getEnabledLocales();\n\n // Check if locales are configured\n if (enabledLocales.length === 0) {\n // No locales configured - show error dialog with guidance\n await dialogService.showError({\n title: 'No Locales Configured',\n message: 'Please configure target locales before translating documents.',\n error: new Error('No translation locales have been configured. Please use the Locale Configuration tool to add target languages.')\n });\n return;\n }\n\n // Extract structured document content\n const documentContent = await contentExtractor.extractStructuredContent(document);\n\n // Validate that we have content to translate\n if (!documentContent.htmlContent || documentContent.htmlContent.trim().length === 0) {\n await dialogService.showError({\n title: 'Translation Failed',\n message: 'No translatable content found in this document.',\n error: new Error('The document does not contain any translatable content.')\n });\n return;\n }\n\n // Load collision resolution config from storage\n const configStorage = new UnifiedConfigStorage(client);\n const collisionConfig = await configStorage.getCollisionResolutionConfig();\n const defaultCreationMode = await configStorage.getDefaultDocumentCreationMode();\n\n // Show locale selection dialog with collision resolution options\n const selectedLocalesResult = await dialogService.showLocaleSelection({\n title: 'Select Target Locales',\n message: `Choose the languages to translate \"${documentContent.title}\" into:`,\n availableLocales: enabledLocales,\n selectedLocales: [],\n selectedDocuments: [document],\n mode: 'single',\n allowMultiple: true,\n required: true,\n showCreationModeOption: true,\n defaultCreationMode: defaultCreationMode,\n showCollisionResolutionOverride: true,\n defaultCollisionResolutionMode: collisionConfig.collisionResolutionMode,\n defaultExistingDocumentHandling: collisionConfig.existingDocumentHandling\n });\n\n // User cancelled locale selection\n if (!selectedLocalesResult || !selectedLocalesResult.locales || selectedLocalesResult.locales.length === 0) {\n return;\n }\n\n const selectedLocales = selectedLocalesResult.locales;\n const creationMode = selectedLocalesResult.creationMode || defaultCreationMode;\n \n // Get collision resolution settings (use override if provided, otherwise use defaults)\n const effectiveCollisionMode: CollisionResolutionMode = selectedLocalesResult.collisionResolutionMode || collisionConfig.collisionResolutionMode;\n const effectiveExistingDocHandling: ExistingDocumentHandling = selectedLocalesResult.existingDocumentHandling || collisionConfig.existingDocumentHandling;\n \n // Configure document creation service with collision settings\n documentCreationService.setCollisionResolutionConfig(effectiveCollisionMode, effectiveExistingDocHandling);\n\n // Ask user for confirmation before creating new document\n const shouldCreateDocument = await dialogService.showConfirmation({\n title: 'Confirm Translation',\n message: `Translate \"${documentContent.title}\" to ${selectedLocales.length} locale(s)?`,\n details: `This will:\\n• Send the translation request for ${selectedLocales.length} locale(s)\\n• Create new documents with translated content\\n• Preserve the original document structure`,\n confirmText: 'Translate & Create Documents',\n cancelText: 'Cancel',\n tone: 'primary'\n });\n\n // User cancelled confirmation\n if (!shouldCreateDocument) {\n return;\n }\n\n // Send translation request\n console.log(`Sending translation request for \"${documentContent.title}\" to ${selectedLocales.length} locale(s)...`);\n console.log('Selected locales:', selectedLocales);\n \n const translationResponse = await translationService.translateDocument(\n documentContent,\n type,\n undefined, // sourceLanguage - use default\n undefined, // targetLanguage - not used for multi-locale\n selectedLocales // targetLocales array\n );\n\n // Handle the response\n if (translationResponse.success) {\n console.log(`Translation completed successfully for \"${documentContent.title}\"`);\n console.log('Translated documents:', translationResponse.translatedDocuments);\n if (translationResponse.requestId) {\n console.log('Request ID:', translationResponse.requestId);\n }\n\n // Get all translated documents (support both new array format and legacy single document format)\n const translatedDocuments = translationResponse.translatedDocuments || \n (translationResponse.translatedContent ? [translationResponse.translatedContent] : []);\n\n if (translatedDocuments.length > 0) {\n console.log(`Creating ${translatedDocuments.length} new translated document(s)...`);\n \n const creationResults = [];\n let successCount = 0;\n let failCount = 0;\n \n // Create a document for each translated document in the response\n for (let i = 0; i < translatedDocuments.length; i++) {\n const translatedContent = translatedDocuments[i];\n \n // Extract TARGET locale from the translated content\n // Priority:\n // 1. translatedContent.locale (document-level locale set by translation service - this IS the target)\n // 2. selectedLocales[i] or selectedLocales[0] (from user selection)\n // NOTE: Do NOT use translatedContent.fields?.locale as that contains the \n // locale FIELD VALUE from the source document, not the translation target\n const targetLocale = (\n translatedContent.locale || \n selectedLocales[i] || \n selectedLocales[0]\n );\n \n console.log(`Creating document ${i + 1}/${translatedDocuments.length} for locale: ${targetLocale}`);\n \n // Create a single-document translation response for this document\n const singleDocumentResponse = {\n ...translationResponse,\n translatedDocuments: [translatedContent],\n translatedContent: translatedContent\n };\n \n const creationResult = await documentCreationService.createDocumentFromTranslation(\n document,\n singleDocumentResponse,\n {\n targetLanguage: targetLocale,\n createAsVariant: true,\n parentDocumentId: document._id,\n creationMode: creationMode,\n // Pass through the in-memory flags for title/body handling\n titleFoundAtTopLevel: documentContent.titleFoundAtTopLevel,\n bodyFoundAtTopLevel: documentContent.bodyFoundAtTopLevel,\n bodyFieldName: documentContent.bodyFieldName,\n // Pass collision resolution options\n collisionResolutionMode: effectiveCollisionMode,\n existingDocumentHandling: effectiveExistingDocHandling\n }\n );\n\n creationResults.push(creationResult);\n\n if (creationResult.success) {\n successCount++;\n console.log(`Document ${i + 1} created successfully with ID: ${creationResult.documentId}`);\n console.log('New document structure:', creationResult.document);\n \n // Log collision resolution info if applicable\n if (creationResult.collisionInfo?.collisionDetected) {\n console.log(`[CollisionHandling] Collision was ${creationResult.collisionInfo.resolutionAction} for document ${i + 1}`);\n }\n } else {\n failCount++;\n console.error(`Failed to create document ${i + 1}:`, creationResult.error);\n }\n }\n\n // Collect slug fallback info\n const slugFallbacks = creationResults\n .filter(r => r.success && r.slugFallback)\n .map(r => r.slugFallback!);\n \n // Collect collision resolution info\n const collisionHandlings = creationResults\n .filter(r => r.success && r.collisionInfo?.collisionDetected)\n .map(r => r.collisionInfo!);\n \n const slugFallbackNote = slugFallbacks.length > 0\n ? `\\n\\n⚠️ Slug fallbacks: ${slugFallbacks.length} document(s) had locale suffix added to slugs (translation did not produce different slugs):\\n${slugFallbacks.map(f => ` • \"${f.originalSlug}\" → \"${f.fallbackSlug}\"`).join('\\n')}`\n : '';\n \n // Build collision handling note\n const collisionNote = collisionHandlings.length > 0\n ? `\\n\\n🔄 Collision handling: ${collisionHandlings.length} existing translation(s) were ${collisionHandlings[0].resolutionAction === 'replaced' ? 'replaced' : 'handled'}.`\n : '';\n\n // Show appropriate success/error dialog based on results\n if (successCount === translatedDocuments.length) {\n // All documents created successfully\n const documentIds = creationResults\n .filter(r => r.success)\n .map(r => r.documentId)\n .join('\\n');\n \n dialogService.showSuccess({\n title: 'Translation Completed',\n message: `Successfully translated \"${documentContent.title}\" to ${successCount} locale(s)`,\n details: `Created ${successCount} new document(s):\\n${documentIds}\\n\\nTarget locale(s): ${selectedLocales.join(', ')}${collisionNote}${slugFallbackNote}`\n });\n } else if (successCount > 0) {\n // Partial success\n const successIds = creationResults\n .filter(r => r.success)\n .map(r => r.documentId)\n .join('\\n');\n const errors = creationResults\n .filter(r => !r.success)\n .map(r => r.error)\n .join('\\n');\n \n await dialogService.showError({\n title: 'Partial Translation Success',\n message: `Created ${successCount} of ${translatedDocuments.length} documents. ${failCount} failed.`,\n error: new Error(`Successfully created:\\n${successIds}\\n\\nErrors:\\n${errors}${slugFallbackNote}`)\n });\n } else {\n // All failed\n const errors = creationResults\n .map(r => r.error)\n .join('\\n');\n \n await dialogService.showError({\n title: 'Document Creation Failed',\n message: 'Translation completed, but failed to create any documents.',\n error: new Error(errors || 'Unknown error during document creation')\n });\n }\n }\n } else {\n console.error(`Translation failed for \"${documentContent.title}\":`, translationResponse.error);\n throw new Error(translationResponse.error || 'Translation request failed');\n }\n\n // Call onComplete if provided to signal success\n if (onComplete) {\n onComplete();\n }\n\n } catch (error) {\n console.error('Translation failed:', error);\n\n // Log user-friendly error message\n const errorMessage = error instanceof Error ? error.message : 'An unexpected error occurred';\n console.error(`Failed to translate document: ${errorMessage}`);\n \n // Show error dialog to user\n await dialogService.showError({\n title: 'Translation Failed',\n message: 'An error occurred during translation.',\n error: error instanceof Error ? error : new Error(errorMessage),\n showRetry: true\n });\n } finally {\n isTranslating = false;\n }\n };\n\n const action: DocumentActionDescription = {\n label: isTranslating ? 'Translating...' : 'Translate',\n icon: TranslateIcon,\n onHandle: handleTranslate,\n tone: 'primary',\n disabled: isTranslating\n };\n\n console.log('translateDocumentAction returning action:', action);\n return action;\n};","import React, { useState, useCallback, useEffect } from 'react';\nimport { Tool, SanityDocument, useClient } from 'sanity';\nimport { TranslateIcon, CheckmarkIcon, CloseIcon, WarningOutlineIcon, RefreshIcon, ChevronDownIcon, ChevronRightIcon } from '@sanity/icons';\nimport { Card, Stack, Text, Button, Flex, Box, Spinner, Badge, Checkbox } from '@sanity/ui';\nimport { \n ContentExtractor, \n BulkTranslationSummary, \n TranslationResponse,\n DocumentCreationService, \n BulkDocumentCreationResult \n} from '@easyling/sanity-connector-shared';\nimport { LocaleService } from '../services/localeService';\nimport { SanityLocaleStorageAdapter } from '../services/localeStorageAdapter';\nimport { useDialogService } from '../services/dialogService';\nimport { OAuthServiceManager } from '../services/oauthServiceManager';\n\ninterface DocumentProcessingStatus {\n documentId: string;\n title: string;\n status: 'pending' | 'processing' | 'completed' | 'failed';\n error?: string;\n response?: TranslationResponse;\n}\n\ninterface DocumentsByType {\n [type: string]: SanityDocument[];\n}\n\ninterface BulkTranslateState {\n isProcessing: boolean;\n isLoadingDocuments: boolean;\n selectedDocuments: SanityDocument[];\n availableDocuments: DocumentsByType;\n selectedTypes: Set<string>;\n selectedDocumentIds: Set<string>;\n expandedTypes: Set<string>;\n summary: BulkTranslationSummary | null;\n error: string | null;\n processingStatus: DocumentProcessingStatus[];\n currentProcessingIndex: number;\n createDocuments: boolean;\n documentCreationResult: BulkDocumentCreationResult | null;\n selectedLocales: string[] | null;\n}\n\n/**\n * Bulk Translation Tool Component\n * Requirements: 2.2, 2.4, 3.1, 3.4, 4.1, 4.3\n */\nconst BulkTranslateTool: React.FC = () => {\n const client = useClient();\n const dialogService = useDialogService();\n \n const [state, setState] = useState<BulkTranslateState>({\n isProcessing: false,\n isLoadingDocuments: false,\n selectedDocuments: [],\n availableDocuments: {},\n selectedTypes: new Set(),\n selectedDocumentIds: new Set(),\n expandedTypes: new Set(),\n summary: null,\n error: null,\n processingStatus: [],\n currentProcessingIndex: -1,\n createDocuments: false,\n documentCreationResult: null,\n selectedLocales: null\n });\n\n /**\n * Fetch all documents from Sanity, grouped by type and ordered by creation date\n */\n const fetchDocuments = useCallback(async () => {\n setState(prev => ({ ...prev, isLoadingDocuments: true, error: null }));\n\n try {\n // Query all documents, excluding system documents, Sanity internal documents, and plugin internal types (EL_*)\n const query = `*[!(_id in path(\"_.**\")) && !(_type match \"sanity.**\") && !(_type match \"EL_*\")] | order(_createdAt desc) {\n _id,\n _type,\n _createdAt,\n _updatedAt,\n _rev,\n title,\n name,\n heading,\n label,\n ...\n }`;\n\n console.log('Fetching documents from Sanity...');\n const documents: SanityDocument[] = await client.fetch(query);\n console.log(`Fetched ${documents.length} documents`);\n\n // Group documents by type\n const documentsByType: DocumentsByType = {};\n documents.forEach(doc => {\n if (!documentsByType[doc._type]) {\n documentsByType[doc._type] = [];\n }\n documentsByType[doc._type].push(doc);\n });\n\n // Log the grouping for debugging\n Object.keys(documentsByType).forEach(type => {\n console.log(`Type \"${type}\": ${documentsByType[type].length} documents`);\n });\n\n setState(prev => ({\n ...prev,\n availableDocuments: documentsByType,\n isLoadingDocuments: false\n }));\n\n } catch (error) {\n console.error('Failed to fetch documents:', error);\n setState(prev => ({\n ...prev,\n error: error instanceof Error ? error.message : 'Failed to fetch documents',\n isLoadingDocuments: false\n }));\n }\n }, [client]);\n\n // Load documents on component mount\n useEffect(() => {\n fetchDocuments();\n }, [fetchDocuments]);\n\n /**\n * Handle document type selection (select/deselect all documents of a type)\n */\n const handleTypeSelection = useCallback((type: string, selected: boolean) => {\n setState(prev => {\n const newSelectedTypes = new Set(prev.selectedTypes);\n const newSelectedDocumentIds = new Set(prev.selectedDocumentIds);\n \n if (selected) {\n newSelectedTypes.add(type);\n // Add all documents of this type to selected documents\n if (prev.availableDocuments[type]) {\n prev.availableDocuments[type].forEach(doc => {\n newSelectedDocumentIds.add(doc._id);\n });\n }\n } else {\n newSelectedTypes.delete(type);\n // Remove all documents of this type from selected documents\n if (prev.availableDocuments[type]) {\n prev.availableDocuments[type].forEach(doc => {\n newSelectedDocumentIds.delete(doc._id);\n });\n }\n }\n\n // Update selected documents array based on selected IDs\n const newSelectedDocuments = Object.values(prev.availableDocuments)\n .flat()\n .filter(doc => newSelectedDocumentIds.has(doc._id));\n\n // Create processing status for selected documents\n const processingStatus: DocumentProcessingStatus[] = newSelectedDocuments.map(doc => ({\n documentId: doc._id,\n title: getDocumentTitle(doc),\n status: 'pending' as const\n }));\n\n return {\n ...prev,\n selectedTypes: newSelectedTypes,\n selectedDocumentIds: newSelectedDocumentIds,\n selectedDocuments: newSelectedDocuments,\n processingStatus,\n summary: null,\n error: null,\n currentProcessingIndex: -1\n };\n });\n }, []);\n\n /**\n * Handle individual document selection\n */\n const handleDocumentSelection = useCallback((document: SanityDocument, selected: boolean) => {\n setState(prev => {\n const newSelectedDocumentIds = new Set(prev.selectedDocumentIds);\n const newSelectedTypes = new Set(prev.selectedTypes);\n \n if (selected) {\n newSelectedDocumentIds.add(document._id);\n } else {\n newSelectedDocumentIds.delete(document._id);\n // If no documents of this type are selected, remove the type from selectedTypes\n const typeDocuments = prev.availableDocuments[document._type] || [];\n const hasOtherSelectedInType = typeDocuments.some(doc => \n doc._id !== document._id && newSelectedDocumentIds.has(doc._id)\n );\n if (!hasOtherSelectedInType) {\n newSelectedTypes.delete(document._type);\n }\n }\n\n // Check if all documents of this type are now selected\n const typeDocuments = prev.availableDocuments[document._type] || [];\n const allTypeDocumentsSelected = typeDocuments.every(doc => \n newSelectedDocumentIds.has(doc._id)\n );\n \n if (allTypeDocumentsSelected && typeDocuments.length > 0) {\n newSelectedTypes.add(document._type);\n }\n\n // Update selected documents array\n const newSelectedDocuments = Object.values(prev.availableDocuments)\n .flat()\n .filter(doc => newSelectedDocumentIds.has(doc._id));\n\n // Create processing status for selected documents\n const processingStatus: DocumentProcessingStatus[] = newSelectedDocuments.map(doc => ({\n documentId: doc._id,\n title: getDocumentTitle(doc),\n status: 'pending' as const\n }));\n\n return {\n ...prev,\n selectedTypes: newSelectedTypes,\n selectedDocumentIds: newSelectedDocumentIds,\n selectedDocuments: newSelectedDocuments,\n processingStatus,\n summary: null,\n error: null,\n currentProcessingIndex: -1\n };\n });\n }, []);\n\n /**\n * Toggle expansion of document type to show individual documents\n */\n const handleTypeExpansion = useCallback((type: string) => {\n setState(prev => {\n const newExpandedTypes = new Set(prev.expandedTypes);\n if (newExpandedTypes.has(type)) {\n newExpandedTypes.delete(type);\n } else {\n newExpandedTypes.add(type);\n }\n return {\n ...prev,\n expandedTypes: newExpandedTypes\n };\n });\n }, []);\n\n /**\n * Select all documents of all types\n */\n const handleSelectAll = useCallback(() => {\n const allTypes = Object.keys(state.availableDocuments);\n const allDocuments = Object.values(state.availableDocuments).flat();\n const allDocumentIds = new Set(allDocuments.map(doc => doc._id));\n \n const processingStatus: DocumentProcessingStatus[] = allDocuments.map(doc => ({\n documentId: doc._id,\n title: getDocumentTitle(doc),\n status: 'pending' as const\n }));\n\n setState(prev => ({\n ...prev,\n selectedTypes: new Set(allTypes),\n selectedDocumentIds: allDocumentIds,\n selectedDocuments: allDocuments,\n processingStatus,\n summary: null,\n error: null,\n currentProcessingIndex: -1,\n documentCreationResult: null\n }));\n }, [state.availableDocuments]);\n\n /**\n * Clear all selections\n */\n const handleClearSelection = useCallback(() => {\n setState(prev => ({\n ...prev,\n selectedTypes: new Set(),\n selectedDocumentIds: new Set(),\n selectedDocuments: [],\n processingStatus: [],\n summary: null,\n error: null,\n currentProcessingIndex: -1,\n documentCreationResult: null\n }));\n }, []);\n\n /**\n * Get document title from various possible fields\n */\n const getDocumentTitle = (doc: SanityDocument): string => {\n const titleFields = ['title', 'name', 'heading', 'label'];\n \n for (const field of titleFields) {\n if (doc[field] && typeof doc[field] === 'string') {\n return doc[field] as string;\n }\n }\n \n return `${doc._type} (${doc._id})`;\n };\n\n const handleBulkTranslate = useCallback(async () => {\n if (state.selectedDocuments.length === 0) {\n await dialogService.showError({\n title: 'No Documents Selected',\n message: 'Please select at least one document to translate.',\n error: new Error('No documents selected for translation')\n });\n return;\n }\n\n try {\n // Get OAuth service manager and check authentication\n // Requirements: 4.1, 4.2, 4.3, 10.5\n const serviceManager = OAuthServiceManager.getInstance(client);\n const authStateManager = serviceManager.getAuthStateManager();\n const authState = authStateManager.getState();\n \n // If OAuth is configured but not authenticated, prompt user to authenticate\n if (serviceManager.isOAuthConfigured() && authState.state !== 'authenticated') {\n await dialogService.showError({\n title: 'Authentication Required',\n message: 'You need to configure your Easyling credentials to use translation services.',\n error: new Error('Please go to the Easyling Configuration tool to enter your access token and project ID.')\n });\n return;\n }\n \n // Initialize locale service\n const storageAdapter = new SanityLocaleStorageAdapter(client);\n const localeService = new LocaleService(storageAdapter);\n\n // Load locale configuration\n await localeService.loadConfig();\n const enabledLocales = localeService.getEnabledLocales();\n\n // Check if locales are configured\n if (enabledLocales.length === 0) {\n await dialogService.showError({\n title: 'No Locales Configured',\n message: 'Please configure target locales before translating documents.',\n error: new Error('No translation locales have been configured. Please use the Locale Configuration tool to add target languages.')\n });\n return;\n }\n\n // Show locale selection dialog\n const selectedLocalesResult = await dialogService.showLocaleSelection({\n title: 'Select Target Locales',\n message: `Choose the languages to translate ${state.selectedDocuments.length} document${state.selectedDocuments.length !== 1 ? 's' : ''} into:`,\n availableLocales: enabledLocales,\n selectedLocales: [],\n selectedDocuments: state.selectedDocuments,\n mode: 'bulk',\n allowMultiple: true,\n required: true,\n showCreationModeOption: true,\n defaultCreationMode: 'draft'\n });\n\n // User cancelled locale selection\n if (!selectedLocalesResult || !selectedLocalesResult.locales || selectedLocalesResult.locales.length === 0) {\n return;\n }\n\n const selectedLocales = selectedLocalesResult.locales;\n const creationMode = selectedLocalesResult.creationMode || 'draft';\n\n // Ask user if they want to create new documents\n const shouldCreateDocuments = await dialogService.showConfirmation({\n title: 'Confirm Bulk Translation',\n message: `Translate ${state.selectedDocuments.length} document${state.selectedDocuments.length !== 1 ? 's' : ''} to ${selectedLocales.length} locale${selectedLocales.length !== 1 ? 's' : ''}?`,\n details: `This will:\\n• Send translation requests for all selected documents\\n• Create new documents with translated content for successful translations\\n• Preserve the original document structures\\n\\nTarget locales: ${selectedLocales.join(', ')}`,\n confirmText: 'Translate & Create Documents',\n cancelText: 'Cancel',\n tone: 'primary'\n });\n\n // User cancelled confirmation\n if (!shouldCreateDocuments) {\n return;\n }\n\n setState(prev => ({\n ...prev,\n isProcessing: true,\n error: null,\n summary: null,\n currentProcessingIndex: 0,\n createDocuments: shouldCreateDocuments,\n documentCreationResult: null,\n selectedLocales\n }));\n\n // Initialize services\n const contentExtractor = new ContentExtractor();\n const translationService = serviceManager.getTranslationService();\n const documentCreationService = new DocumentCreationService(client);\n\n console.log(`Starting bulk translation for ${state.selectedDocuments.length} documents`);\n\n // Extract content from all selected documents\n const extractedContents = await contentExtractor.extractBulkStructuredContent(\n state.selectedDocuments\n );\n\n // Filter out documents with no content and update status\n const validContents = extractedContents.filter(content => {\n const hasContent = content.htmlContent && content.htmlContent.trim().length > 0;\n if (!hasContent) {\n // Update status for documents with no content\n setState(prev => ({\n ...prev,\n processingStatus: prev.processingStatus.map(status =>\n status.documentId === content.documentId\n ? { ...status, status: 'failed', error: 'No translatable content found' }\n : status\n )\n }));\n }\n return hasContent;\n });\n\n if (validContents.length === 0) {\n throw new Error('No translatable content found in selected documents');\n }\n\n console.log(`Processing ${validContents.length} documents with valid content`);\n\n // Process documents one by one with progress updates\n const summary: BulkTranslationSummary = {\n totalDocuments: state.selectedDocuments.length,\n processedDocuments: 0,\n failedDocuments: 0,\n requests: [],\n responses: []\n };\n\n for (let i = 0; i < validContents.length; i++) {\n const content = validContents[i];\n \n // Update current processing index and document status\n setState(prev => ({\n ...prev,\n currentProcessingIndex: i,\n processingStatus: prev.processingStatus.map(status =>\n status.documentId === content.documentId\n ? { ...status, status: 'processing' }\n : status\n )\n }));\n\n try {\n // Prepare and send translation request with selected locales\n const request = translationService.prepareTranslationRequest(\n content,\n undefined, // documentType - use default\n undefined, // sourceLanguage - use default\n undefined, // targetLanguage - not used for multi-locale\n selectedLocales // targetLocales array\n );\n const response = await translationService.sendTranslationRequest(request);\n\n // Update summary\n summary.requests.push(request);\n summary.responses.push(response);\n\n if (response.success) {\n summary.processedDocuments++;\n // Update document status to completed\n setState(prev => ({\n ...prev,\n processingStatus: prev.processingStatus.map(status =>\n status.documentId === content.documentId\n ? { ...status, status: 'completed', response }\n : status\n )\n }));\n } else {\n summary.failedDocuments++;\n // Update document status to failed\n setState(prev => ({\n ...prev,\n processingStatus: prev.processingStatus.map(status =>\n status.documentId === content.documentId\n ? { ...status, status: 'failed', error: response.error, response }\n : status\n )\n }));\n }\n\n // Add a small delay to make progress visible\n await new Promise(resolve => setTimeout(resolve, 500));\n\n } catch (error) {\n console.error(`Failed to process document ${content.documentId}:`, error);\n summary.failedDocuments++;\n \n const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';\n summary.responses.push({\n success: false,\n error: errorMessage\n });\n\n // Update document status to failed\n setState(prev => ({\n ...prev,\n processingStatus: prev.processingStatus.map(status =>\n status.documentId === content.documentId\n ? { ...status, status: 'failed', error: errorMessage }\n : status\n )\n }));\n }\n }\n\n // Create documents if user requested and we have successful translations\n let documentCreationResult: BulkDocumentCreationResult | null = null;\n \n if (shouldCreateDocuments && summary.processedDocuments > 0) {\n console.log('Creating new documents from successful translations...');\n \n // Get successful translations and their corresponding original documents\n const successfulResponses = summary.responses.filter(response => response.success);\n const successfulDocuments = state.selectedDocuments.filter(doc => {\n const responseIndex = summary.responses.findIndex((_, index) => {\n const request = summary.requests[index];\n return request && request.documentId === doc._id;\n });\n return responseIndex >= 0 && summary.responses[responseIndex].success;\n });\n\n if (successfulDocuments.length > 0 && successfulResponses.length > 0) {\n documentCreationResult = await documentCreationService.createBulkDocumentsFromTranslations(\n successfulDocuments,\n successfulResponses,\n {\n targetLanguage: 'translated',\n createAsVariant: true,\n creationMode: creationMode\n }\n );\n\n console.log('Document Creation Summary:', {\n totalDocuments: documentCreationResult.totalDocuments,\n successfulCreations: documentCreationResult.successfulCreations,\n failedCreations: documentCreationResult.failedCreations,\n errors: documentCreationResult.errors,\n slugFallbacks: documentCreationResult.slugFallbacks\n });\n }\n }\n\n // Log bulk operation summary\n console.log('Bulk Translation Summary:', {\n timestamp: new Date().toISOString(),\n totalDocuments: summary.totalDocuments,\n processedDocuments: summary.processedDocuments,\n failedDocuments: summary.failedDocuments,\n successRate: summary.totalDocuments > 0\n ? ((summary.processedDocuments / summary.totalDocuments) * 100).toFixed(2) + '%'\n : '0%'\n });\n\n setState(prev => ({\n ...prev,\n summary,\n documentCreationResult,\n isProcessing: false,\n currentProcessingIndex: -1\n }));\n\n console.log('Bulk translation completed:', summary);\n\n // Show completion message to user\n if (shouldCreateDocuments && documentCreationResult) {\n const slugFallbackNote = documentCreationResult.slugFallbacks && documentCreationResult.slugFallbacks.length > 0\n ? `\\n\\n⚠️ Slug fallbacks: ${documentCreationResult.slugFallbacks.length} document(s) had locale suffix added to slugs (translation did not produce different slugs).`\n : '';\n \n dialogService.showSuccess({\n title: 'Bulk Translation Completed',\n message: `Successfully translated ${summary.processedDocuments} of ${summary.totalDocuments} documents to ${selectedLocales.length} locale${selectedLocales.length !== 1 ? 's' : ''}`,\n details: `Translations: ${summary.processedDocuments}/${summary.totalDocuments} successful\\nDocuments created: ${documentCreationResult.successfulCreations}/${documentCreationResult.totalDocuments} successful\\nTarget locales: ${selectedLocales.join(', ')}${slugFallbackNote}\\n\\nCheck the console for detailed results and new document structures.`\n });\n } else {\n dialogService.showSuccess({\n title: 'Bulk Translation Completed',\n message: `Successfully translated ${summary.processedDocuments} of ${summary.totalDocuments} documents`,\n details: `Translations: ${summary.processedDocuments}/${summary.totalDocuments} successful\\nTarget locales: ${selectedLocales.join(', ')}\\n\\nTranslation responses have been logged to the console for verification.`\n });\n }\n\n } catch (error) {\n console.error('Bulk translation failed:', error);\n \n // Show error dialog\n await dialogService.showError({\n title: 'Bulk Translation Failed',\n message: 'An error occurred during bulk translation.',\n error: error instanceof Error ? error : new Error('An unexpected error occurred')\n });\n\n setState(prev => ({\n ...prev,\n error: error instanceof Error ? error.message : 'An unexpected error occurred',\n isProcessing: false,\n currentProcessingIndex: -1\n }));\n }\n }, [state.selectedDocuments, client, dialogService]);\n\n\n\n return (\n <Card padding={4}>\n <Stack space={4}>\n <Text size={2} weight=\"semibold\">\n Bulk Document Translation\n </Text>\n \n <Text size={1} muted>\n Select multiple documents to translate them in batch. Translation requests will be logged to the console for verification.\n </Text>\n\n {/* Document Selection Section */}\n <Card padding={3} border>\n <Stack space={3}>\n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1} weight=\"medium\">\n Document Selection\n </Text>\n <Flex gap={2}>\n <Button\n text=\"Refresh\"\n icon={RefreshIcon}\n onClick={fetchDocuments}\n disabled={state.isLoadingDocuments}\n mode=\"ghost\"\n fontSize={1}\n />\n {state.selectedDocuments.length > 0 && (\n <Button\n text=\"Clear All\"\n tone=\"critical\"\n mode=\"ghost\"\n onClick={handleClearSelection}\n fontSize={1}\n />\n )}\n </Flex>\n </Flex>\n\n {state.isLoadingDocuments ? (\n <Flex align=\"center\" gap={2}>\n <Spinner size={1} />\n <Text size={1} muted>Loading documents...</Text>\n </Flex>\n ) : Object.keys(state.availableDocuments).length === 0 ? (\n <Text size={1} muted>No documents found</Text>\n ) : (\n <Stack space={3}>\n {/* Summary and Select All */}\n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1}>\n Selected: {state.selectedDocuments.length} documents from {state.selectedTypes.size} types\n </Text>\n <Button\n text=\"Select All Types\"\n onClick={handleSelectAll}\n mode=\"ghost\"\n fontSize={1}\n />\n </Flex>\n\n {/* Document Types */}\n <Stack space={2}>\n <Text size={1} weight=\"medium\">\n Document Types\n </Text>\n \n {Object.entries(state.availableDocuments)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([type, documents]) => {\n const isExpanded = state.expandedTypes.has(type);\n const selectedInType = documents.filter(doc => state.selectedDocumentIds.has(doc._id)).length;\n const isPartiallySelected = selectedInType > 0 && selectedInType < documents.length;\n const isFullySelected = selectedInType === documents.length;\n \n return (\n <Card key={type} padding={2} border>\n <Stack space={2}>\n {/* Type Header */}\n <Flex align=\"center\" justify=\"space-between\">\n <Flex align=\"center\" gap={2}>\n <Checkbox\n checked={isFullySelected}\n indeterminate={isPartiallySelected}\n onChange={(event) => handleTypeSelection(type, event.currentTarget.checked)}\n />\n <Button\n icon={isExpanded ? ChevronDownIcon : ChevronRightIcon}\n mode=\"ghost\"\n onClick={() => handleTypeExpansion(type)}\n style={{ minWidth: 'auto', padding: '4px' }}\n />\n <Box>\n <Text size={1} weight=\"medium\">\n {type}\n </Text>\n <Text size={0} muted>\n {selectedInType}/{documents.length} selected • Latest: {new Date(documents[0]._createdAt).toLocaleDateString()}\n </Text>\n </Box>\n </Flex>\n <Badge \n tone={selectedInType > 0 ? \"positive\" : \"primary\"} \n fontSize={0}\n >\n {selectedInType > 0 ? `${selectedInType}/${documents.length}` : documents.length}\n </Badge>\n </Flex>\n\n {/* Individual Documents (when expanded) */}\n {isExpanded && (\n <Box style={{ marginLeft: '32px' }}>\n <Stack space={1}>\n {documents.map((doc) => (\n <Card key={doc._id} padding={2} tone=\"transparent\" border>\n <Flex align=\"center\" justify=\"space-between\">\n <Flex align=\"center\" gap={2}>\n <Checkbox\n checked={state.selectedDocumentIds.has(doc._id)}\n onChange={(event) => handleDocumentSelection(doc, event.currentTarget.checked)}\n />\n <Box>\n <Text size={1}>\n {getDocumentTitle(doc)}\n </Text>\n <Text size={0} muted>\n {doc._id} • {new Date(doc._createdAt).toLocaleDateString()}\n </Text>\n </Box>\n </Flex>\n {state.selectedDocumentIds.has(doc._id) && (\n <Badge tone=\"positive\" fontSize={0}>\n Selected\n </Badge>\n )}\n </Flex>\n </Card>\n ))}\n </Stack>\n </Box>\n )}\n </Stack>\n </Card>\n );\n })}\n </Stack>\n\n {/* Selected Documents Preview */}\n {state.selectedDocuments.length > 0 && (\n <Stack space={2}>\n <Text size={1} weight=\"medium\">\n Selected Documents ({state.selectedDocuments.length})\n </Text>\n \n <Box style={{ maxHeight: '200px', overflowY: 'auto' }}>\n <Stack space={1}>\n {state.selectedDocuments.slice(0, 10).map((doc) => (\n <Card key={doc._id} padding={2} tone=\"primary\">\n <Flex align=\"center\" justify=\"space-between\">\n <Box>\n <Text size={1} weight=\"medium\">\n {getDocumentTitle(doc)}\n </Text>\n <Text size={0} muted>\n {doc._type} • {new Date(doc._createdAt).toLocaleDateString()}\n </Text>\n </Box>\n <Badge tone=\"primary\" fontSize={0}>\n {doc._type}\n </Badge>\n </Flex>\n </Card>\n ))}\n {state.selectedDocuments.length > 10 && (\n <Text size={0} muted style={{ textAlign: 'center', padding: '8px' }}>\n ... and {state.selectedDocuments.length - 10} more documents\n </Text>\n )}\n </Stack>\n </Box>\n </Stack>\n )}\n </Stack>\n )}\n </Stack>\n </Card>\n\n {/* Translation Action Section */}\n {state.selectedDocuments.length > 0 && (\n <Card padding={3} border>\n <Stack space={3}>\n <Text size={1} weight=\"medium\">\n Translation Action\n </Text>\n \n {state.selectedLocales && state.selectedLocales.length > 0 && (\n <Card padding={2} tone=\"primary\">\n <Text size={1}>\n Target Locales: {state.selectedLocales.join(', ')}\n </Text>\n </Card>\n )}\n \n <Button\n text={state.isProcessing ? 'Processing...' : `Translate ${state.selectedDocuments.length} Documents`}\n icon={state.isProcessing ? Spinner : TranslateIcon}\n onClick={handleBulkTranslate}\n tone=\"primary\"\n disabled={state.isProcessing}\n />\n </Stack>\n </Card>\n )}\n\n {/* Progress Indicators */}\n {state.isProcessing && state.processingStatus.length > 0 && (\n <Card padding={3} border>\n <Stack space={3}>\n <Text size={1} weight=\"medium\">\n Translation Progress\n </Text>\n \n {/* Overall Progress */}\n <Stack space={2}>\n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1}>\n Overall Progress: {state.currentProcessingIndex + 1} of {state.selectedDocuments.length}\n </Text>\n <Text size={1} muted>\n {state.currentProcessingIndex >= 0 \n ? `${Math.round(((state.currentProcessingIndex + 1) / state.selectedDocuments.length) * 100)}%`\n : '0%'\n }\n </Text>\n </Flex>\n \n <Box style={{ \n width: '100%', \n height: '8px', \n backgroundColor: '#e0e0e0', \n borderRadius: '4px',\n overflow: 'hidden'\n }}>\n <Box style={{\n width: `${state.currentProcessingIndex >= 0 \n ? ((state.currentProcessingIndex + 1) / state.selectedDocuments.length) * 100 \n : 0}%`,\n height: '100%',\n backgroundColor: '#0066cc',\n transition: 'width 0.3s ease'\n }} />\n </Box>\n </Stack>\n\n {/* Individual Document Status */}\n <Stack space={2}>\n <Text size={1} weight=\"medium\">\n Document Status\n </Text>\n \n {state.processingStatus.map((status) => (\n <Card key={status.documentId} padding={2} border>\n <Flex align=\"center\" justify=\"space-between\">\n <Box flex={1}>\n <Text size={1} weight=\"medium\">\n {status.title}\n </Text>\n <Text size={0} muted>\n ID: {status.documentId}\n </Text>\n {status.error && (\n <Text size={0} style={{ color: 'red' }}>\n Error: {status.error}\n </Text>\n )}\n </Box>\n \n <Box>\n {status.status === 'pending' && (\n <Badge tone=\"default\" fontSize={0}>\n Pending\n </Badge>\n )}\n {status.status === 'processing' && (\n <Badge tone=\"primary\" fontSize={0}>\n <Flex align=\"center\" gap={1}>\n <Spinner size={0} />\n Processing\n </Flex>\n </Badge>\n )}\n {status.status === 'completed' && (\n <Badge tone=\"positive\" fontSize={0}>\n <Flex align=\"center\" gap={1}>\n <CheckmarkIcon />\n Completed\n </Flex>\n </Badge>\n )}\n {status.status === 'failed' && (\n <Badge tone=\"critical\" fontSize={0}>\n <Flex align=\"center\" gap={1}>\n <CloseIcon />\n Failed\n </Flex>\n </Badge>\n )}\n </Box>\n </Flex>\n </Card>\n ))}\n </Stack>\n </Stack>\n </Card>\n )}\n\n {/* Error Display */}\n {state.error && (\n <Card padding={3} tone=\"critical\" border>\n <Text size={1} weight=\"medium\">\n Error: {state.error}\n </Text>\n </Card>\n )}\n\n {/* Summary Display */}\n {state.summary && (\n <Card padding={3} tone={state.summary.failedDocuments === 0 ? \"positive\" : \"caution\"} border>\n <Stack space={3}>\n <Flex align=\"center\" gap={2}>\n {state.summary.failedDocuments === 0 ? (\n <CheckmarkIcon style={{ color: 'green' }} />\n ) : (\n <WarningOutlineIcon style={{ color: 'orange' }} />\n )}\n <Text size={1} weight=\"medium\">\n Translation Summary\n </Text>\n </Flex>\n \n <Stack space={2}>\n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1}>Total Documents:</Text>\n <Badge tone=\"primary\">{state.summary.totalDocuments}</Badge>\n </Flex>\n \n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1}>Successfully Processed:</Text>\n <Badge tone=\"positive\">{state.summary.processedDocuments}</Badge>\n </Flex>\n \n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1}>Failed:</Text>\n <Badge tone=\"critical\">{state.summary.failedDocuments}</Badge>\n </Flex>\n \n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1}>Success Rate:</Text>\n <Badge tone={state.summary.failedDocuments === 0 ? \"positive\" : \"caution\"}>\n {state.summary.totalDocuments > 0\n ? `${((state.summary.processedDocuments / state.summary.totalDocuments) * 100).toFixed(1)}%`\n : '0%'\n }\n </Badge>\n </Flex>\n </Stack>\n\n {/* Detailed Results */}\n {state.processingStatus.length > 0 && (\n <Stack space={2}>\n <Text size={1} weight=\"medium\">\n Detailed Results\n </Text>\n \n {state.processingStatus.map((status) => (\n <Card key={status.documentId} padding={2} border>\n <Flex align=\"center\" justify=\"space-between\">\n <Box flex={1}>\n <Text size={1} weight=\"medium\">\n {status.title}\n </Text>\n <Text size={0} muted>\n ID: {status.documentId}\n </Text>\n {status.error && (\n <Text size={0} style={{ color: 'red' }}>\n Error: {status.error}\n </Text>\n )}\n </Box>\n \n <Box>\n {status.status === 'pending' && (\n <Badge tone=\"default\" fontSize={0}>\n Pending\n </Badge>\n )}\n {status.status === 'processing' && (\n <Badge tone=\"primary\" fontSize={0}>\n <Flex align=\"center\" gap={1}>\n <Spinner size={0} />\n Processing\n </Flex>\n </Badge>\n )}\n {status.status === 'completed' && (\n <Badge tone=\"positive\" fontSize={0}>\n <Flex align=\"center\" gap={1}>\n <CheckmarkIcon />\n Completed\n </Flex>\n </Badge>\n )}\n {status.status === 'failed' && (\n <Badge tone=\"critical\" fontSize={0}>\n <Flex align=\"center\" gap={1}>\n <CloseIcon />\n Failed\n </Flex>\n </Badge>\n )}\n </Box>\n </Flex>\n </Card>\n ))}\n </Stack>\n )}\n </Stack>\n </Card>\n )}\n\n {/* Document Creation Results */}\n {state.documentCreationResult && (\n <Card padding={3} tone={state.documentCreationResult.failedCreations === 0 ? \"positive\" : \"caution\"} border>\n <Stack space={3}>\n <Flex align=\"center\" gap={2}>\n {state.documentCreationResult.failedCreations === 0 ? (\n <CheckmarkIcon style={{ color: 'green' }} />\n ) : (\n <WarningOutlineIcon style={{ color: 'orange' }} />\n )}\n <Text size={1} weight=\"medium\">\n Document Creation Summary\n </Text>\n </Flex>\n \n <Stack space={2}>\n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1}>Documents to Create:</Text>\n <Badge tone=\"primary\">{state.documentCreationResult.totalDocuments}</Badge>\n </Flex>\n \n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1}>Successfully Created:</Text>\n <Badge tone=\"positive\">{state.documentCreationResult.successfulCreations}</Badge>\n </Flex>\n \n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1}>Failed to Create:</Text>\n <Badge tone=\"critical\">{state.documentCreationResult.failedCreations}</Badge>\n </Flex>\n \n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1}>Creation Success Rate:</Text>\n <Badge tone={state.documentCreationResult.failedCreations === 0 ? \"positive\" : \"caution\"}>\n {state.documentCreationResult.totalDocuments > 0\n ? `${((state.documentCreationResult.successfulCreations / state.documentCreationResult.totalDocuments) * 100).toFixed(1)}%`\n : '0%'\n }\n </Badge>\n </Flex>\n </Stack>\n\n {/* Creation Errors */}\n {state.documentCreationResult.errors.length > 0 && (\n <Stack space={2}>\n <Text size={1} weight=\"medium\">\n Creation Errors\n </Text>\n <Box style={{ maxHeight: '150px', overflowY: 'auto' }}>\n <Stack space={1}>\n {state.documentCreationResult.errors.map((error, index) => (\n <Card key={index} padding={2} tone=\"critical\">\n <Text size={0} style={{ color: 'red' }}>\n {error}\n </Text>\n </Card>\n ))}\n </Stack>\n </Box>\n </Stack>\n )}\n\n {/* Slug Fallbacks */}\n {state.documentCreationResult.slugFallbacks && state.documentCreationResult.slugFallbacks.length > 0 && (\n <Stack space={2}>\n <Flex align=\"center\" gap={2}>\n <WarningOutlineIcon style={{ color: '#f5a623' }} />\n <Text size={1} weight=\"medium\">\n Slug Fallbacks Applied ({state.documentCreationResult.slugFallbacks.length})\n </Text>\n </Flex>\n <Text size={0} muted>\n The following documents had unchanged slugs from translation. Locale suffix was automatically applied to avoid conflicts.\n </Text>\n <Box style={{ maxHeight: '200px', overflowY: 'auto' }}>\n <Stack space={1}>\n {state.documentCreationResult.slugFallbacks.map((fallback, index) => (\n <Card key={index} padding={2} tone=\"caution\" border>\n <Stack space={1}>\n <Text size={1} weight=\"medium\">\n {fallback.documentId}\n </Text>\n <Flex align=\"center\" gap={2}>\n <Badge tone=\"default\" fontSize={0}>{fallback.originalSlug}</Badge>\n <Text size={0}>→</Text>\n <Badge tone=\"positive\" fontSize={0}>{fallback.fallbackSlug}</Badge>\n </Flex>\n <Text size={0} muted>\n Locale: {fallback.locale}\n </Text>\n </Stack>\n </Card>\n ))}\n </Stack>\n </Box>\n </Stack>\n )}\n </Stack>\n </Card>\n )}\n </Stack>\n </Card>\n );\n};\n\n/**\n * Bulk Translation Tool Definition\n * Requirements: 2.1, 2.5, 4.1, 4.2\n */\nexport const bulkTranslateTool: Tool = {\n name: 'bulk-translate',\n title: 'Bulk Translate',\n icon: TranslateIcon,\n component: BulkTranslateTool\n};","/**\n * Document action for managing DNT (Do Not Translate) field preferences\n * \n * Now uses document-type-based configuration: DNT settings apply to ALL documents\n * of the same type, not just individual document instances.\n */\n\nimport { DocumentActionComponent, DocumentActionProps } from 'sanity';\nimport { BlockElementIcon } from '@sanity/icons';\nimport { useCallback } from 'react';\nimport { useDialogService } from '../services/dialogService';\nimport { getDNTStorage } from '../services/dntServiceManager';\n\n/**\n * Document action for managing DNT fields\n */\nexport const manageDNTFieldsAction: DocumentActionComponent = (props: DocumentActionProps) => {\n const { type, draft, published } = props;\n const dialogService = useDialogService();\n\n const document = draft || published;\n\n // Don't show DNT action for plugin configuration documents\n const pluginConfigTypes = ['EL_PluginConfiguration', 'EL_oauth-config', 'EL_translation-plugin-config'];\n if (pluginConfigTypes.includes(type)) {\n return {\n label: 'Manage Translation Fields',\n icon: BlockElementIcon,\n disabled: true,\n hidden: true\n };\n }\n\n const handleManageDNT = useCallback(async () => {\n if (!document) {\n await dialogService.showError({\n title: 'No Document',\n message: 'Cannot manage DNT fields: No document available'\n });\n return;\n }\n\n // Get all translatable fields from the document\n const fields: Array<{ path: string; value: any; type: string }> = [];\n const extractFields = (obj: any, parentPath: string = '') => {\n if (!obj || typeof obj !== 'object') return;\n\n for (const [key, value] of Object.entries(obj)) {\n // Skip system fields\n if (key.startsWith('_')) continue;\n\n const fieldPath = parentPath ? `${parentPath}.${key}` : key;\n\n // Check if it's a translatable field type\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n Array.isArray(value)\n ) {\n fields.push({\n path: fieldPath,\n value,\n type: typeof value\n });\n } else if (value && typeof value === 'object') {\n // Recursively extract nested fields\n extractFields(value, fieldPath);\n }\n }\n };\n\n extractFields(document);\n\n // Load current DNT preferences for this document type\n const dntStorage = getDNTStorage();\n const dntFields = await dntStorage.getFieldsForType(type);\n\n // Create field list with DNT status\n const fieldList = fields.map(field => ({\n ...field,\n isDNT: dntFields[field.path] || false\n }));\n\n // Show dialog with field list\n const message = fieldList.length > 0\n ? `Found ${fieldList.length} translatable fields in this ${type} document. Use the field badges to toggle DNT status. Settings apply to ALL ${type} documents.`\n : 'No translatable fields found in this document.';\n\n const confirmed = await dialogService.showConfirmation({\n title: 'Manage Translation Fields',\n message,\n confirmText: fieldList.length > 0 ? `Clear All DNT Settings for ${type}` : 'OK',\n cancelText: 'Close',\n tone: 'primary'\n });\n\n if (confirmed && fieldList.length > 0) {\n // Clear all DNT preferences for this document type\n await dntStorage.clearFieldsForType(type);\n await dialogService.showSuccess({\n title: 'DNT Settings Cleared',\n message: `All fields in ${type} documents are now marked as translatable.`\n });\n }\n }, [document, type, dialogService]);\n\n return {\n label: 'Manage Translation Fields',\n icon: BlockElementIcon,\n onHandle: handleManageDNT,\n disabled: !document\n };\n};\n\n","/**\n * Password Input Component for Sanity\n * \n * Custom input component that obscures sensitive token values in Sanity Studio\n */\n\nimport React from 'react';\nimport { TextInput } from '@sanity/ui';\nimport { StringInputProps, set, unset } from 'sanity';\n\n/**\n * Password Input Component\n * \n * Renders a password-type input field that obscures the value\n */\nexport const PasswordInput: React.FC<StringInputProps> = (props) => {\n const { elementProps, onChange, value = '' } = props;\n\n const handleChange = React.useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n const nextValue = event.currentTarget.value;\n onChange(nextValue ? set(nextValue) : unset());\n },\n [onChange]\n );\n\n return (\n <TextInput\n {...elementProps}\n type=\"password\"\n value={value}\n onChange={handleChange}\n />\n );\n};\n\n","/**\n * DNT Field Badge Component\n * Displays a badge on fields indicating their translation status and allows toggling\n * \n * Now uses document-type-based configuration: toggling DNT for a field applies to\n * ALL documents of the same type.\n */\n\nimport React, { useState, useEffect, useCallback } from 'react';\nimport { Badge, Button, Flex, Tooltip } from '@sanity/ui';\nimport { TranslateIcon, BlockElementIcon } from '@sanity/icons';\nimport { getDNTStorage } from '../../services/dntServiceManager';\n\ninterface DNTFieldBadgeProps {\n documentId: string;\n documentType: string;\n fieldPath: string;\n fieldTitle?: string;\n}\n\nexport function DNTFieldBadge(props: DNTFieldBadgeProps) {\n const { documentType, fieldPath, fieldTitle } = props;\n const [isDNT, setIsDNT] = useState(false);\n const [isLoading, setIsLoading] = useState(true);\n\n // Load initial DNT status\n useEffect(() => {\n const loadDNTStatus = async () => {\n try {\n setIsLoading(true);\n const dntStorage = getDNTStorage();\n const status = await dntStorage.getFieldDNT(documentType, fieldPath);\n setIsDNT(status);\n } catch (error) {\n console.error('Failed to load DNT status:', error);\n } finally {\n setIsLoading(false);\n }\n };\n\n if (documentType && fieldPath) {\n loadDNTStatus();\n }\n }, [documentType, fieldPath]);\n\n // Toggle DNT status (applies to all documents of this type)\n const handleToggle = useCallback(async () => {\n try {\n const dntStorage = getDNTStorage();\n const newStatus = await dntStorage.toggleFieldDNT(documentType, fieldPath);\n setIsDNT(newStatus);\n } catch (error) {\n console.error('Failed to toggle DNT status:', error);\n }\n }, [documentType, fieldPath]);\n\n if (isLoading) {\n return null;\n }\n\n const tooltipContent = isDNT\n ? `This field will NOT be translated for ALL ${documentType} documents. Click to make it translatable.`\n : `This field will be translated. Click to mark as \"Do Not Translate\" for ALL ${documentType} documents.`;\n\n return (\n <Tooltip\n content={\n <Flex padding={2} direction=\"column\" gap={2}>\n <div style={{ fontWeight: 'bold' }}>\n {fieldTitle || fieldPath}\n </div>\n <div>{tooltipContent}</div>\n </Flex>\n }\n placement=\"top\"\n >\n <Button\n mode=\"bleed\"\n padding={2}\n onClick={handleToggle}\n style={{ minHeight: 'auto' }}\n >\n <Badge\n tone={isDNT ? 'critical' : 'positive'}\n mode={isDNT ? 'default' : 'outline'}\n >\n <Flex align=\"center\" gap={1}>\n {isDNT ? <BlockElementIcon /> : <TranslateIcon />}\n <span style={{ fontSize: '0.75rem' }}>\n {isDNT ? 'DNT' : 'Translate'}\n </span>\n </Flex>\n </Badge>\n </Button>\n </Tooltip>\n );\n}\n\n","/**\n * DNT Field Component\n * A wrapper component that adds DNT toggle functionality to any field\n */\n\nimport React from 'react';\nimport { ObjectInputProps, StringInputProps, NumberInputProps, BooleanInputProps, ArrayOfObjectsInputProps } from 'sanity';\nimport { Stack } from '@sanity/ui';\nimport { DNTFieldBadge } from './DNTFieldBadge';\n\ntype FieldInputProps = \n | ObjectInputProps \n | StringInputProps \n | NumberInputProps \n | BooleanInputProps \n | ArrayOfObjectsInputProps;\n\ninterface DNTFieldComponentProps {\n documentId?: string;\n documentType?: string;\n}\n\n/**\n * Higher-order component that wraps field components with DNT functionality\n */\nexport function withDNTBadge<P extends FieldInputProps>(\n Component: React.ComponentType<P>\n): React.ComponentType<P & DNTFieldComponentProps> {\n return function DNTFieldComponent(props: P & DNTFieldComponentProps) {\n const { documentId, documentType, ...fieldProps } = props;\n const typedProps = fieldProps as P;\n \n // Get field information\n const fieldPath = (typedProps as any).path?.join('.') || '';\n const fieldTitle = (typedProps as any).schemaType?.title;\n\n // Don't show badge if we don't have necessary info\n if (!documentId || !fieldPath) {\n return <Component {...typedProps} />;\n }\n\n return (\n <Stack space={2}>\n <Component {...typedProps} />\n <div style={{ marginTop: '0.25rem' }}>\n <DNTFieldBadge\n documentId={documentId}\n documentType={documentType || 'document'}\n fieldPath={fieldPath}\n fieldTitle={fieldTitle}\n />\n </div>\n </Stack>\n );\n };\n}\n\n","/**\n * DNT Field Input Component\n * Wraps any field with a DNT toggle badge\n * \n * Now uses document-type-based configuration: toggling DNT for a field applies to\n * ALL documents of the same type.\n */\n\nimport React, { useCallback, useEffect, useState } from 'react';\nimport { FieldProps, useFormValue } from 'sanity';\nimport { Box, Button, Flex, Stack, Text, Tooltip } from '@sanity/ui';\nimport { TranslateIcon, BlockElementIcon } from '@sanity/icons';\nimport { getDNTStorage } from '../../services/dntServiceManager';\n\n/**\n * Field component that adds DNT badge\n */\nexport function DNTFieldInput(props: FieldProps) {\n const { renderDefault, schemaType, path } = props;\n \n // Get document from form context using Sanity hook\n const document = useFormValue([]) as any;\n \n // Get document info\n const documentId = document?._id;\n const documentType = document?._type;\n const fieldPath = path?.join('.') || '';\n const fieldTitle = schemaType?.title || fieldPath;\n \n // Don't show DNT badges for plugin configuration documents\n const pluginConfigTypes = ['EL_PluginConfiguration', 'EL_oauth-config', 'EL_translation-plugin-config'];\n if (documentType && pluginConfigTypes.includes(documentType)) {\n return renderDefault(props);\n }\n \n const [isDNT, setIsDNT] = useState(false);\n const [isLoading, setIsLoading] = useState(true);\n\n // Load DNT status on mount (based on document type)\n useEffect(() => {\n if (!documentType || !fieldPath) {\n setIsLoading(false);\n return;\n }\n\n const loadDNTStatus = async () => {\n try {\n const dntStorage = getDNTStorage();\n const status = await dntStorage.getFieldDNT(documentType, fieldPath);\n setIsDNT(status);\n } catch (error) {\n console.error('Failed to load DNT status:', error);\n } finally {\n setIsLoading(false);\n }\n };\n\n loadDNTStatus();\n }, [documentType, fieldPath]);\n\n // Toggle DNT status (applies to all documents of this type)\n const handleToggleDNT = useCallback(async () => {\n if (!documentType || !fieldPath) return;\n\n try {\n const dntStorage = getDNTStorage();\n const newStatus = await dntStorage.toggleFieldDNT(documentType, fieldPath);\n setIsDNT(newStatus);\n } catch (error) {\n console.error('Failed to toggle DNT:', error);\n }\n }, [documentType, fieldPath]);\n\n // Don't show badge for system fields or if no document ID\n if (!documentId || !fieldPath || fieldPath.startsWith('_')) {\n return renderDefault(props);\n }\n\n const tooltipContent = isDNT\n ? `This field will NOT be translated for ALL ${documentType} documents. Click to make it translatable.`\n : `This field will be translated. Click to mark as \"Do Not Translate\" for ALL ${documentType} documents.`;\n\n return (\n <Stack space={2}>\n <Box>{renderDefault(props)}</Box>\n {!isLoading && (\n <Flex align=\"center\" gap={2} paddingTop={2}>\n <Tooltip\n content={\n <Box padding={2}>\n <Text size={1}>{tooltipContent}</Text>\n </Box>\n }\n placement=\"top\"\n >\n <Button\n mode=\"ghost\"\n tone={isDNT ? 'critical' : 'positive'}\n padding={2}\n fontSize={1}\n onClick={handleToggleDNT}\n icon={isDNT ? BlockElementIcon : TranslateIcon}\n text={isDNT ? 'Do Not Translate' : 'Will Translate'}\n />\n </Tooltip>\n <Text muted size={1}>\n Translation: <strong>{isDNT ? 'Disabled' : 'Enabled'}</strong> for {fieldTitle}\n </Text>\n </Flex>\n )}\n </Stack>\n );\n}\n\n","/**\n * DNT (Do Not Translate) Defaults Utility\n * \n * Determines whether a field should default to DNT based on:\n * - Field type (slug, date, datetime, reference, image, file, geopoint, number, boolean)\n * - Field name patterns (containing \"author\" or \"contributor\")\n * - Group/fieldset name patterns (containing \"date\" or \"time\")\n */\n\n/**\n * Field types that are inherently non-translatable\n * These fields contain data that should not be modified by translation\n */\nexport const NON_TRANSLATABLE_TYPES: string[] = [\n 'date',\n 'datetime',\n 'reference',\n 'image',\n 'file',\n 'geopoint',\n 'number',\n 'boolean'\n];\n\n/**\n * Field name patterns that indicate DNT by default (case-insensitive)\n * Fields with names containing these strings should not be translated\n */\nexport const DNT_FIELD_NAME_PATTERNS: string[] = [\n 'author',\n 'contributor',\n 'date',\n 'time',\n 'lastModification',\n 'lastModified',\n '_key',\n '_ref',\n '_type',\n '_id',\n '_rev',\n '_createdAt',\n '_updatedAt',\n];\n\n/**\n * Group/fieldset name patterns that indicate all contained fields should be DNT (case-insensitive)\n */\nexport const DNT_GROUP_NAME_PATTERNS: string[] = [\n 'date',\n 'time'\n];\n\n/**\n * Context information about a field's location in the schema\n */\nexport interface FieldContext {\n /** The field path (e.g., 'title', 'content.author') */\n fieldPath: string;\n /** The field name (last segment of path) */\n fieldName: string;\n /** The Sanity field type (e.g., 'string', 'date', 'slug') */\n fieldType?: string;\n /** Name of the group this field belongs to, if any */\n groupName?: string;\n /** Name of the fieldset this field belongs to, if any */\n fieldsetName?: string;\n}\n\n/**\n * Result of DNT default computation\n */\nexport interface DNTDefaultResult {\n /** Whether the field should default to DNT */\n shouldBeDNT: boolean;\n /** Reason for the DNT default decision */\n reason: string;\n}\n\n/**\n * Check if a field type is inherently non-translatable\n * \n * @param fieldType - The Sanity field type\n * @returns True if the field type should not be translated\n */\nexport function isNonTranslatableType(fieldType: string | undefined): boolean {\n if (!fieldType) {\n return false;\n }\n return NON_TRANSLATABLE_TYPES.includes(fieldType.toLowerCase());\n}\n\n/**\n * Check if a field name matches DNT patterns\n * \n * @param fieldName - The field name to check\n * @returns Object with match status and matched pattern\n */\nexport function matchesDNTFieldNamePattern(fieldName: string): { matches: boolean; pattern?: string } {\n if (!fieldName) {\n return { matches: false };\n }\n \n const lowerName = fieldName.toLowerCase();\n for (const pattern of DNT_FIELD_NAME_PATTERNS) {\n if (lowerName.includes(pattern.toLowerCase())) {\n return { matches: true, pattern };\n }\n }\n \n return { matches: false };\n}\n\n/**\n * Check if a group or fieldset name matches DNT patterns\n * \n * @param groupOrFieldsetName - The group or fieldset name to check\n * @returns Object with match status and matched pattern\n */\nexport function matchesDNTGroupPattern(groupOrFieldsetName: string | undefined): { matches: boolean; pattern?: string } {\n if (!groupOrFieldsetName) {\n return { matches: false };\n }\n \n const lowerName = groupOrFieldsetName.toLowerCase();\n for (const pattern of DNT_GROUP_NAME_PATTERNS) {\n if (lowerName.includes(pattern.toLowerCase())) {\n return { matches: true, pattern };\n }\n }\n \n return { matches: false };\n}\n\n/**\n * Compute the default DNT status for a field based on its context\n * \n * Priority order:\n * 1. Non-translatable field type (slug, date, etc.)\n * 2. Field name contains \"author\" or \"contributor\"\n * 3. Field is in a group/fieldset containing \"date\" or \"time\"\n * \n * @param context - Field context information\n * @returns DNT default result with reason\n */\nexport function computeDNTDefault(context: FieldContext): DNTDefaultResult {\n // 1. Check field type first (highest priority)\n if (isNonTranslatableType(context.fieldType)) {\n return {\n shouldBeDNT: true,\n reason: `Field type \"${context.fieldType}\" is non-translatable`\n };\n }\n \n // 2. Check field name patterns\n const nameMatch = matchesDNTFieldNamePattern(context.fieldName);\n if (nameMatch.matches) {\n return {\n shouldBeDNT: true,\n reason: `Field name contains \"${nameMatch.pattern}\" pattern`\n };\n }\n \n // 3. Check group name patterns\n const groupMatch = matchesDNTGroupPattern(context.groupName);\n if (groupMatch.matches) {\n return {\n shouldBeDNT: true,\n reason: `Field is in group containing \"${groupMatch.pattern}\" pattern`\n };\n }\n \n // 4. Check fieldset name patterns\n const fieldsetMatch = matchesDNTGroupPattern(context.fieldsetName);\n if (fieldsetMatch.matches) {\n return {\n shouldBeDNT: true,\n reason: `Field is in fieldset containing \"${fieldsetMatch.pattern}\" pattern`\n };\n }\n \n // Default: translatable\n return {\n shouldBeDNT: false,\n reason: 'Field is translatable by default'\n };\n}\n\n/**\n * Determine if a field should show DNT badge based on translatability\n * Only translatable field types should show the badge\n * \n * @param fieldType - The Sanity field type\n * @returns True if the field should show a DNT badge\n */\nexport function shouldShowDNTBadge(fieldType: string | undefined): boolean {\n // Translatable types that should show DNT badge\n const translatableTypes = ['string', 'text', 'url', 'email', 'array'];\n \n if (!fieldType) {\n return false;\n }\n \n return translatableTypes.includes(fieldType.toLowerCase());\n}\n\n/**\n * Get a human-readable description of the DNT status for debugging\n * \n * @param context - Field context information\n * @param storedDNT - The stored DNT status (if any)\n * @returns Debug description\n */\nexport function getDNTDebugInfo(context: FieldContext, storedDNT?: boolean): string {\n const defaultResult = computeDNTDefault(context);\n \n const parts: string[] = [\n `Path: ${context.fieldPath}`,\n `Name: ${context.fieldName}`,\n `Type: ${context.fieldType || 'unknown'}`\n ];\n \n if (context.groupName) {\n parts.push(`Group: ${context.groupName}`);\n }\n \n if (context.fieldsetName) {\n parts.push(`Fieldset: ${context.fieldsetName}`);\n }\n \n parts.push(`Default DNT: ${defaultResult.shouldBeDNT} (${defaultResult.reason})`);\n \n if (storedDNT !== undefined) {\n parts.push(`Stored DNT: ${storedDNT}`);\n }\n \n return parts.join(' | ');\n}\n","/**\n * Debug DNT Badge Component\n * \n * Displays debug information about the DNT status of a field.\n * This badge is shown on ALL fields (not just translatable ones) when debug mode is enabled.\n * It shows whether the field will be included in the translation request and its effective DNT status.\n */\n\nimport React, { useEffect, useState, useMemo } from 'react';\nimport { FieldProps, useFormValue } from 'sanity';\nimport { Badge, Box, Card, Flex, Stack, Text, Tooltip } from '@sanity/ui';\nimport { InfoOutlineIcon } from '@sanity/icons';\nimport { getDNTStorage } from '../../services/dntServiceManager';\nimport { computeDNTDefault, FieldContext, isNonTranslatableType } from '../../utils/dntDefaults';\n\nexport type DebugDNTBadgeProps = FieldProps & {\n /** Name of the group this field belongs to */\n groupName?: string;\n /** Name of the fieldset this field belongs to */\n fieldsetName?: string;\n};\n\n/**\n * Debug DNT Badge Component\n * Shows the effective DNT status for all fields when debug mode is enabled\n */\nexport function DebugDNTBadge(props: DebugDNTBadgeProps) {\n const { renderDefault, schemaType, path, groupName, fieldsetName } = props;\n \n // Get document from form context\n const document = useFormValue([]) as any;\n \n // Get document and field info\n const documentType = document?._type;\n const fieldPath = path?.join('.') || '';\n const fieldName = path?.[path.length - 1]?.toString() || fieldPath;\n const fieldType = schemaType?.type?.name || schemaType?.jsonType;\n \n // State for stored DNT status\n const [storedDNT, setStoredDNT] = useState<boolean | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n \n // Build field context for DNT computation\n const fieldContext: FieldContext = useMemo(() => ({\n fieldPath,\n fieldName,\n fieldType,\n groupName,\n fieldsetName\n }), [fieldPath, fieldName, fieldType, groupName, fieldsetName]);\n \n // Compute the default DNT status\n const defaultResult = useMemo(() => computeDNTDefault(fieldContext), [fieldContext]);\n \n // Load stored DNT status\n useEffect(() => {\n if (!documentType || !fieldPath) {\n setIsLoading(false);\n return;\n }\n\n const loadDNTStatus = async () => {\n try {\n const dntStorage = getDNTStorage();\n const status = await dntStorage.getFieldDNT(documentType, fieldPath);\n // Only set storedDNT if there's an explicit setting\n const allFields = await dntStorage.getFieldsForType(documentType);\n if (fieldPath in allFields) {\n setStoredDNT(status);\n } else {\n setStoredDNT(undefined);\n }\n } catch (error) {\n console.error('Failed to load DNT status for debug badge:', error);\n } finally {\n setIsLoading(false);\n }\n };\n\n loadDNTStatus();\n }, [documentType, fieldPath]);\n \n // Determine effective DNT status\n const effectiveDNT = storedDNT !== undefined ? storedDNT : defaultResult.shouldBeDNT;\n \n // Determine if field is translatable type\n const isTranslatable = !isNonTranslatableType(fieldType);\n \n // Determine if field will be included in translation request\n // Non-translatable types are typically excluded from the payload\n const willBeInPayload = isTranslatable;\n \n // Badge color based on status\n const badgeColor = effectiveDNT ? 'critical' : 'positive';\n const statusText = effectiveDNT ? 'DNT' : 'TRANSLATE';\n \n // Debug info for tooltip\n const debugLines = [\n `Field: ${fieldPath}`,\n `Type: ${fieldType || 'unknown'}`,\n `Group: ${groupName || 'none'}`,\n `Fieldset: ${fieldsetName || 'none'}`,\n '',\n `Default DNT: ${defaultResult.shouldBeDNT}`,\n `Reason: ${defaultResult.reason}`,\n '',\n `Stored Setting: ${storedDNT !== undefined ? storedDNT : 'none (using default)'}`,\n `Effective DNT: ${effectiveDNT}`,\n '',\n `In Payload: ${willBeInPayload ? 'Yes' : 'No (non-translatable type)'}`,\n willBeInPayload ? `dnt field value: ${effectiveDNT}` : ''\n ].filter(Boolean);\n \n return (\n <Stack space={2}>\n <Box>{renderDefault(props)}</Box>\n {!isLoading && (\n <Card tone=\"transparent\" padding={2} radius={2} style={{ backgroundColor: 'rgba(0,0,0,0.03)' }}>\n <Flex align=\"center\" gap={2}>\n <Tooltip\n content={\n <Card padding={3} radius={2} shadow={1}>\n <Stack space={2}>\n <Text weight=\"bold\" size={1}>DNT Debug Info</Text>\n {debugLines.map((line, i) => (\n <Text key={i} size={0} muted={!line.startsWith('Effective') && !line.startsWith('In Payload')}>\n {line || ' '}\n </Text>\n ))}\n </Stack>\n </Card>\n }\n placement=\"top\"\n portal\n >\n <Flex align=\"center\" gap={1} style={{ cursor: 'help' }}>\n <InfoOutlineIcon />\n <Badge \n tone={willBeInPayload ? badgeColor : 'default'}\n mode={willBeInPayload ? 'default' : 'outline'}\n fontSize={0}\n >\n {willBeInPayload ? statusText : 'EXCLUDED'}\n </Badge>\n </Flex>\n </Tooltip>\n <Text size={0} muted>\n {willBeInPayload \n ? `Debug: Will ${effectiveDNT ? 'NOT ' : ''}be translated`\n : `Debug: Not in payload (${fieldType} type)`\n }\n {storedDNT === undefined && willBeInPayload && ' (default)'}\n </Text>\n </Flex>\n </Card>\n )}\n </Stack>\n );\n}\n\n","// Main plugin definition\nimport { definePlugin, LayoutProps, useClient, FieldProps } from 'sanity';\nimport React, { useEffect, useState, createContext, useContext } from 'react';\nimport { translateDocumentAction } from './actions/translateDocument';\nimport { bulkTranslateTool } from './actions/bulkTranslate';\nimport { manageDNTFieldsAction } from './actions/manageDNTFields';\nimport { createPluginConfigSchema, legacyLocaleConfigSchema } from './config/pluginConfig';\nimport { DialogProvider } from './services/dialogService';\nimport { OAuthServiceManager } from './services/oauthServiceManager';\nimport { DNTServiceManager } from './services/dntServiceManager';\nimport { UnifiedConfigStorage } from '@easyling/sanity-connector-shared';\nimport { PasswordInput } from './components/config/PasswordInput';\nimport { DNTFieldInput, DebugDNTBadge } from './components/dnt';\n\n/**\n * Context for plugin configuration state\n */\ninterface PluginConfigContextType {\n debugMode: boolean;\n}\n\nconst PluginConfigContext = createContext<PluginConfigContextType>({ debugMode: false });\n\n/**\n * Hook to access plugin configuration\n */\nexport function usePluginConfig() {\n return useContext(PluginConfigContext);\n}\n\nconsole.log('Loading sanity-translation-plugin...');\n\n/**\n * Legacy OAuth configuration schema (deprecated)\n * Kept for backward compatibility and automatic migration\n * @deprecated Now uses unified EL_PluginConfiguration document\n */\nconst legacyOAuthConfigSchema = {\n name: 'EL_oauth-config',\n title: 'Easyling Configuration (Legacy)',\n type: 'document',\n hidden: true, // Hide from UI - legacy documents will be migrated automatically\n fields: [\n {\n name: 'projectId',\n title: 'Project ID',\n type: 'string',\n description: 'Your Easyling project ID',\n validation: (Rule: any) => Rule.required()\n },\n {\n name: 'accessToken',\n title: 'Access Token',\n type: 'string',\n description: 'Long-lived access token provided by Easyling (hidden for security)',\n validation: (Rule: any) => Rule.required(),\n components: {\n input: PasswordInput\n }\n },\n {\n name: 'lastUpdated',\n title: 'Last Updated',\n type: 'datetime',\n readOnly: true\n }\n ]\n};\n\n// Studio Layout wrapper component to provide DialogProvider and initialize services\nfunction StudioLayout(props: LayoutProps) {\n const client = useClient({ apiVersion: '2023-01-01' });\n\n // Track initialization state\n const [isInitialized, setIsInitialized] = useState(false);\n const [debugMode, setDebugMode] = useState(false);\n\n // Initialize services on mount\n useEffect(() => {\n const initializeServices = async () => {\n try {\n // Initialize OAuth service manager\n const oauthServiceManager = OAuthServiceManager.getInstance(client);\n await oauthServiceManager.initialize();\n \n // Initialize DNT service manager\n const dntServiceManager = DNTServiceManager.getInstance(client);\n dntServiceManager.initialize(client);\n \n // Load debug mode configuration\n const configStorage = new UnifiedConfigStorage(client);\n const debugModeEnabled = await configStorage.getDebugMode();\n setDebugMode(debugModeEnabled);\n \n console.log('Services initialized successfully, debug mode:', debugModeEnabled);\n setIsInitialized(true);\n } catch (error) {\n console.error('Failed to initialize services:', error);\n setIsInitialized(true); // Still set to true to prevent blocking\n }\n };\n\n initializeServices();\n }, [client]);\n\n // Subscribe to configuration changes for debug mode\n useEffect(() => {\n if (!isInitialized) return;\n\n const query = `*[_id == \"sanity-translation-plugin.config\"][0]`;\n const subscription = client.listen(query).subscribe((update: any) => {\n if (update.result?.debugMode !== undefined) {\n setDebugMode(update.result.debugMode);\n console.log('Debug mode updated:', update.result.debugMode);\n }\n });\n\n return () => subscription.unsubscribe();\n }, [client, isInitialized]);\n\n return (\n <PluginConfigContext.Provider value={{ debugMode }}>\n <DialogProvider>\n {props.renderDefault(props)}\n </DialogProvider>\n </PluginConfigContext.Provider>\n );\n}\n\n/**\n * Field wrapper component that handles DNT badge and debug mode\n */\nfunction FieldWrapper(props: FieldProps) {\n const { debugMode } = usePluginConfig();\n const fieldType = props.schemaType?.type?.name;\n const fieldName = props.schemaType?.name;\n const fieldPath = props.path?.join('.');\n \n // Extract group and fieldset information from schema\n const groupName = (props.schemaType as any)?.group;\n const fieldsetName = (props.schemaType as any)?.fieldset;\n \n // Blacklist: field names that should never show any badge\n const blacklistedFieldNames = ['locale', '_type', '_id', '_rev', '_createdAt', '_updatedAt'];\n const isBlacklistedName = blacklistedFieldNames.includes(fieldName || '') || \n blacklistedFieldNames.some(f => fieldPath?.includes(f));\n \n // Blacklist: field types that should never show interactive DNT badge (non-translatable types)\n const nonTranslatableTypes = ['date', 'datetime', 'image', 'file', 'reference', 'boolean', 'object', 'document', 'slug'];\n const isNonTranslatableType = fieldType && nonTranslatableTypes.includes(fieldType);\n \n // Translatable field types (types that contain text/content that can be translated)\n const translatableTypes = ['string', 'text', 'number', 'url', 'email', 'array'];\n const isTranslatableType = fieldType && translatableTypes.includes(fieldType);\n \n // Don't show any badges for blacklisted fields\n if (isBlacklistedName) {\n return props.renderDefault(props);\n }\n \n // Show interactive DNT badge for translatable types\n const shouldShowInteractiveDNT = isTranslatableType && !isNonTranslatableType;\n \n // If debug mode is enabled, show debug badge for ALL field types (except blacklisted)\n if (debugMode) {\n // Pass group and fieldset info to the debug badge\n return DebugDNTBadge({\n ...props,\n groupName,\n fieldsetName\n } as any);\n }\n \n // Show interactive DNT badge only for translatable types\n if (shouldShowInteractiveDNT) {\n return DNTFieldInput(props);\n }\n \n // Return default for other field types\n return props.renderDefault(props);\n}\n\nexport default definePlugin({\n name: 'sanity-translation-plugin',\n studio: {\n components: {\n layout: StudioLayout\n }\n },\n document: {\n actions: (prev) => {\n console.log('Document actions being registered, previous actions:', prev.length);\n const newActions = [...prev, translateDocumentAction, manageDNTFieldsAction];\n console.log('New actions array length:', newActions.length);\n return newActions;\n }\n },\n form: {\n components: {\n field: (props: FieldProps) => {\n // Wrap in a component to use hooks\n return <FieldWrapper {...props} />;\n }\n }\n },\n tools: (prev) => {\n console.log('Tools being registered, previous tools:', prev.length);\n // Only register bulk translate tool - config is now in unified EL_PluginConfiguration document\n const newTools = [...prev, bulkTranslateTool];\n console.log('New tools array length:', newTools.length);\n return newTools;\n },\n schema: {\n types: [\n // New unified configuration schema (EL_PluginConfiguration) with password input\n createPluginConfigSchema(PasswordInput),\n \n // Legacy schemas kept for migration compatibility\n legacyLocaleConfigSchema,\n legacyOAuthConfigSchema\n ]\n }\n});\n"],"names":["__importDefault","this","mod","__esModule","Object","defineProperty","exports","value","Metadata","TranslatableField","Content_FieldsEntry","Content","TranslationRequestPayload","protobufPackage","minimal_1","isSet","encode","message","writer","default","Writer","create","undefined","content","uint32","fork","ldelim","project","string","format","metadata","decode","input","length","reader","Reader","end","len","pos","tag","skipType","fromJSON","object","globalThis","String","toJSON","obj","base","fromPartial","body","title","slug","entries","fields","forEach","key","entry4","reduce","acc","k","v","dnt","bool","type","path","Boolean","documentId","documentType","sourceLanguage","targetLanguage","targetLocales","push","Array","isArray","map","e","TranslatedDocument_FieldsEntry","TranslatedDocument","TranslationResponse","translation_request_1","success","translatedDocuments","sourceLocale","error","requestId","locale","module","fn","ctx","params","arguments","offset","index","pending","Promise","resolve","reject","err","apply","base64","p","n","charAt","Math","ceil","b64","s64","i","buffer","start","t","parts","chunk","j","b","fromCharCode","slice","join","invalidEncoding","c","charCodeAt","Error","test","EventEmitter","_listeners","prototype","on","evt","off","listeners","splice","emit","args","factory","Float32Array","f32","f8b","Uint8Array","le","writeFloat_f32_cpy","val","buf","writeFloat_f32_rev","readFloat_f32_cpy","readFloat_f32_rev","writeFloatLE","writeFloatBE","readFloatLE","readFloatBE","writeFloat_ieee754","writeUint","sign","isNaN","round","exponent","floor","log","LN2","pow","readFloat_ieee754","readUint","uint","mantissa","NaN","Infinity","bind","writeUintLE","writeUintBE","readUintLE","readUintBE","Float64Array","f64","writeDouble_f64_cpy","writeDouble_f64_rev","readDouble_f64_cpy","readDouble_f64_rev","writeDoubleLE","writeDoubleBE","readDoubleLE","readDoubleBE","writeDouble_ieee754","off0","off1","readDouble_ieee754","lo","hi","inquire","moduleName","eval","replace","keys","alloc","size","SIZE","MAX","slab","call","utf8","read","write","c1","c2","protobuf","configure","util","_configure","BufferWriter","BufferReader","build","rpc","roots","LongBits","indexOutOfRange","writeLength","RangeError","create_array","Buffer","isBuffer","readLongVarint","bits","readFixed32_end","readFixed64","_slice","subarray","int32","sint32","fixed32","sfixed32","float","double","bytes","nativeBuffer","constructor","skip","wireType","BufferReader_","Long","merge","int64","uint64","sint64","zzDecode","fixed64","sfixed64","utf8Slice","min","toString","Service","rpcImpl","requestDelimited","responseDelimited","TypeError","rpcCall","method","requestCtor","responseCtor","request","callback","self","asPromise","finish","response","setTimeout","endedByRPC","zero","toNumber","zzEncode","zeroHash","fromNumber","from","isString","parseInt","fromString","low","high","unsigned","toLong","fromHash","hash","toHash","mask","part0","part1","part2","dst","src","ifNotSet","newError","name","CustomError","properties","get","captureStackTrace","stack","writable","enumerable","configurable","set","pool","isNode","g","process","versions","node","global","window","emptyArray","freeze","emptyObject","isInteger","Number","isFinite","isObject","isset","prop","hasOwnProperty","utf8Write","_Buffer_from","_Buffer_allocUnsafe","newBuffer","sizeOrArray","dcodeIO","key2Re","key32Re","key64Re","longToHash","longFromHash","fromBits","lcFirst","str","toLowerCase","substring","ProtocolError","oneOfGetter","fieldNames","fieldMap","oneOfSetter","toJSONOptions","longs","enums","json","encoding","allocUnsafe","Op","next","noop","State","head","tail","states","writeByte","VarintOp","writeVarint64","writeFixed32","_push","writeBytes","reset","BufferWriter_","writeStringBuffer","writeBytesBuffer","copy","byteLength","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","d","definition","o","Function","DNTStorageAdapter","configStorage","getFieldsForType","getDNTFieldsForType","console","setFieldDNT","fieldPath","setDNTField","toggleFieldDNT","newStatus","toggleDNTField","getFieldDNT","getDNTFieldStatus","clearFieldsForType","clearDNTFieldsForType","getAllDNTFields","getPreferences","_documentId","warn","savePreferences","preferences","clearPreferences","LegacyDNTStorageAdapter","getStorageKey","STORAGE_KEY_PREFIX","stored","localStorage","getItem","JSON","parse","toStore","updatedAt","Date","toISOString","setItem","stringify","removeItem","migrateToUnified","UNIFIED_CONFIG_DOC_ID","UNIFIED_CONFIG_DOC_TYPE","UnifiedConfigStorage","client","convertDNTArrayToMap","dntConfigurations","config","field","convertDNTMapToArray","dntFieldMap","array","fieldArray","_key","load","doc","fetch","id","dntFieldConfigurations","projectId","accessToken","translationApiEndpoint","requestContentType","responseAcceptHeader","defaultDocumentCreationMode","collisionResolutionMode","existingDocumentHandling","locales","defaultLocale","debugMode","version","lastUpdated","save","_id","_type","createOrReplace","update","updates","merged","delete","loadOAuth","saveOAuth","oauthConfig","loadLocale","saveLocale","localeConfig","currentValue","getTranslationEndpoint","getRequestContentType","getResponseAcceptHeader","getDefaultDocumentCreationMode","getCollisionResolutionMode","getExistingDocumentHandling","getCollisionResolutionConfig","setCollisionResolutionConfig","mode","handling","getDebugMode","setDebugMode","enabled","DNTServiceManager","dntStorage","getInstance","instance","initialize","unifiedStorage","getDNTStorage","isInitialized","computeDNTDefault","context","DNT_FIELD_NAME_PATTERNS","DNT_GROUP_NAME_PATTERNS","fieldType","includes","shouldBeDNT","reason","fieldNameLower","fieldName","pattern","groupName","groupNameLower","fieldsetName","fieldsetNameLower","ATOMIC_SANITY_TYPES","Set","buildGroqPath","documentContext","ContentExtractor","inferSanityType","isSanitySpecialType","has","shouldFlattenObject","flattenObjectToFields","basePath","docContext","startsWith","flattenArrayToFields","addLeafField","every","item","extractedValue","processArray","defaultDNT","itemPath","current","dateValue","extractDocumentContent","document","convertToHtml","html","processField","trim","extractStructuredContent","foundAtTopLevel","titleFoundAtTopLevel","extractTitle","extractSlug","bodyContent","bodyFoundAtTopLevel","bodyFieldName","separateContentAndFields","extractedTitle","documentHasTopLevelTitle","documentHasTopLevelBody","enhancedFields","applyDNTPreferences","htmlContent","fieldContextMap","storedDntFields","fieldValue","split","pop","hasStoredPreference","extractionDnt","isDNT","typedField","extractBulkContent","documents","results","extractBulkStructuredContent","structuredContent","processObject","wrapInHtml","listItem","listType","processPortableTextBlockContent","processPortableTextBlock","block","style","children","child","text","marks","mark","href","escapeHtml","_ref","alt","caption","asset","lat","lng","toLocaleDateString","hex","alpha","contentFields","metadataFields","nestedBody","findBodyInNestedFields","contentField","nestedPath","found","itemBasePath","slugFields","titleFields","nestedTitle","findTitleInNestedFields","titleField","htmlEscapeMap","char","TranslationService","placeholderEndpoint","setAuthToken","token","clearAuth","setConfiguration","endpoint","convertPayloadToProtobuf","payload","protoFields","protoPayload","convertPayloadToProtobufJSON","normalizeTranslatedFields","normalizedFields","convertProtobufBinaryToResponse","binaryData","protoResponse","protoField","parsedValue","convertProtobufJSONToResponse","jsonData","originalDoc","originalValue","prepareTranslationRequest","translatableFields","fromContent","willUse","translateDocument","sendTranslationRequest","logTranslationRequest","headers","protobufJSON","ok","status","arrayBuffer","data","protoError","translations","translation","translatedContent","targetLocale","timestamp","processBulkTranslation","contents","summary","totalDocuments","processedDocuments","failedDocuments","requests","responses","localeCount","logBulkTranslationSummary","successRate","toFixed","setEndpoint","getEndpoint","CollisionDetectionError","code","details","super","CollisionDetectionService","detectCollision","options","sourceDocumentId","cleanSourceId","parentMatch","findByParentReference","detected","existingDocument","matchedBy","slugMatch","findBySlugAndLocale","typeFilter","queryWithLocale","queryWithIdPattern","sourceId","sourceIdWithDrafts","idPattern","result","detectBulkCollisions","Map","DocumentCreationService","defaultCreationMode","collisionDetectionService","defaultCollisionResolutionMode","defaultExistingDocumentHandling","setDefaultCreationMode","setDefaultCollisionResolutionMode","setDefaultExistingDocumentHandling","replaceExistingDocument","newDocument","creationMode","existingId","isExistingDraft","documentToSave","_createdAt","_rev","_updatedAt","replacedDocument","draftId","draftDoc","publishedId","publishedDoc","handleExistingDocument","createDocumentFromTranslation","originalDocument","translationResponse","inputValidation","validateInputsForDocumentCreation","isValid","errors","titleFoundAtTopLevelFromOptions","translatedContentKeys","responseValidation","validateTranslationResponseForCreation","mergeTranslatedContent","validationResult","validateDocumentStructure","businessValidation","validateBusinessRules","slugFallbackInfo","slugNeedsFallback","originalSlug","fallbackSlug","effectiveCreationMode","effectiveCollisionMode","effectiveExistingDocHandling","collisionInfo","collisionResult","parentDocumentId","translatedSlug","collisionDetected","existingDocumentId","replaceResult","resolutionAction","existingDocumentAction","slugFallback","handleResult","createdDocument","sanityError","formatErrorMessage","createAsVariant","documentHasContent","newSlug","hasContentInNestedFields","baseMessage","contextInfo","createBulkDocumentsFromTranslations","originalDocuments","translationResponses","successfulCreations","failedCreations","rollbackInfo","canRollback","createdDocumentIds","rollbackInstructions","slugFallbacks","validationErrors","validateBulkTranslationResponses","createdDocuments","preCreationValidation","singleDocumentResponse","creationResult","originalId","errorMessage","fallback","createRollbackPlan","parseFieldPath","segments","groqPrefixMatch","match","cleanPath","segmentRegex","exec","propertyName","keyValue","lastIndex","unflattenFields","fieldKey","actualValue","endsWith","isHtmlContent","convertHtmlToPortableText","originalCurrent","segment","isLastSegment","arrayItem","find","originalItem","assign","getOriginalValueByPath","pathParts","part","targetLang","generateNewDocumentId","shouldWriteTopLevelTitle","originalDocumentTitle","originalDocumentHasTitle","translatedContentTitle","newDocumentTitleBefore","hasTitle","titleNotEmpty","shouldWriteTopLevelBody","hasTranslatedBody","bodyFoundAtTopLevelFromOptions","bodyFieldNameFromOptions","originalHasBody","originalHasContent","portableTextContent","fieldWritten","unflattenedFields","processedValue","processTranslatedField","fieldsToClean","parentDocument","translatedValue","finalValue","blocks","htmlTagRegex","tagName","generateBlockKey","getBlockStyle","parseInlineContent","markDefs","remainingContent","cleanContent","generateSpanKey","now","random","substr","portableTextFields","validatePortableTextArray","slugObj","blockObj","childObj","autoTranslateDocumentTypes","getAutoTranslateDocumentTypes","setAutoTranslateDocumentTypes","types","HtmlFormatter","unescapeHtml","htmlUnescapeMap","formatHtml","preserveWhitespace","escapeSpecialChars","minifyOutput","addLineBreaks","formatted","cleanHtml","allowedTags","tagsToAllow","tagPattern","RegExp","wrapContent","wrapper","className","stripHtml","validateHtml","lineBreaksToParagraphs","filter","paragraph","truncateHtml","maxLength","suffix","truncated","lastCompleteTag","lastIndexOf","htmlFormatter","Validator","validateSanityDocument","warnings","requireTitle","requireContent","allowEmptyFields","maxContentLength","some","documentSize","validateDocumentContent","validateExtendedDocumentContent","basicValidation","validateTranslationPayload","requireMetadata","maxPayloadSize","validateHtmlStructure","htmlValidation","validateHtmlContent","payloadSize","unescapedChars","validateDocumentArray","documentIds","validation","warning","add","validateEndpoint","url","URL","protocol","hostname","validator","createDNTStorageAdapter","async","LOCALE_CODE_REGEX","validateLocaleCode","validateLocaleDefinition","displayName","createdAt","isValidISODate","validateLocaleConfig","localeCodes","localeValidation","localeExists","getEnabledLocales","findLocaleByCode","dateString","date","getTime","RadioWithDefault","props","onChange","defaultValue","renderDefault","createPluginConfigSchema","PasswordInputComponent","description","group","components","initialValue","placeholder","Rule","custom","list","layout","hidden","parent","of","required","regex","invert","preview","select","subtitle","prepare","readOnly","groups","pluginConfigSchema","legacyLocaleConfigSchema","media","defaultLocaleConfig","commonLocales","createLocaleDefinition","updateLocaleDefinition","LocaleServiceError","LocaleService","storageAdapter","initialConfig","loadConfig","loadedConfig","originalError","saveConfig","configToSave","getConfig","getAllLocales","getLocaleByCode","hasLocale","addLocale","fullLocale","updateLocale","localeIndex","findIndex","l","existingLocale","updatedLocale","removeLocale","setDefaultLocale","clearDefaultLocale","validateCurrentConfig","resetToDefault","importConfig","exportConfig","LEGACY_LOCALE_CONFIG_DOC_ID","SanityLocaleStorageAdapter","legacyConfig","loadLegacy","deleteLegacy","ConfirmationDialog","open","confirmText","cancelText","tone","closable","onConfirm","onCancel","confirmButtonRef","focus","header","onClose","onClickOutside","width","role","padding","space","weight","muted","ref","onClick","SuccessDialog","autoCloseTimeout","closeButtonRef","timer","clearTimeout","radius","ErrorDialog","showRetry","retryText","onRetry","primaryButtonRef","marginTop","language","LocaleSelectionDialog","availableLocales","selectedLocales","initialSelectedLocales","selectedDocuments","allowMultiple","showCreationModeOption","showCollisionResolutionOverride","onConfirmWithOptions","setSelectedLocales","setCreationMode","searchQuery","setSearchQuery","validationError","setValidationError","searchInputRef","useOverrideCollision","setUseOverrideCollision","setCollisionResolutionMode","setExistingDocumentHandling","filteredLocales","query","handleLocaleToggle","localeCode","newSelected","clear","handleConfirm","selectedLocaleArray","handleKeyDown","event","preventDefault","ctrlKey","addEventListener","removeEventListener","documentCount","icon","currentTarget","border","justify","align","gap","fontSize","allFilteredCodes","disabled","maxHeight","overflowY","shadow","cursor","tabIndex","onKeyDown","checked","flex","color","DialogContext","useDialogService","DialogProvider","currentDialog","setCurrentDialog","dialogQueue","setDialogQueue","processNextDialog","queue","rest","enqueueDialog","dialogItem","closeCurrentDialog","showConfirmation","showLocaleSelection","showSuccess","catch","showError","closeAll","dialog","handleConfirmationConfirm","handleConfirmationCancel","handleLocaleSelectionConfirm","handleLocaleSelectionConfirmWithOptions","handleLocaleSelectionCancel","handleSuccessClose","handleErrorClose","handleErrorRetry","contextValue","Provider","DialogService","contextRef","setContext","dialogService","OAuthErrorType","OAuthError","getUserMessage","INVALID_CONFIG","NETWORK_ERROR","AUTH_FAILED","STORAGE_ERROR","isRecoverable","OAuthService","validateConfig","hasAccessToken","getAccessToken","getProjectId","AUTH_DATA_STORAGE_KEY","TokenStorage","storeAuthData","dataToStore","storedAt","serialized","getAuthData","clearAuthData","SyntaxError","isTokenExpired","getValidAccessToken","VALID_TRANSITIONS","unauthenticated","authenticated","AuthStateManager","tokenStorage","subscribers","currentState","state","isValidTransition","fromState","toState","getState","setState","newState","projectName","to","notifySubscribers","stateCopy","subscribe","authData","logout","LEGACY_OAUTH_CONFIG_DOC_ID","OAuthConfigStorage","OAuthServiceManager","oauthService","initialized","authStateManager","translationService","oauthConfigStorage","unifiedConfigStorage","resetInstance","setupConfigListener","loadOAuthConfig","setupTranslationServiceAuth","listen","saveAuth","setupTranslationServiceEndpoint","endpointError","getOAuthService","getTokenStorage","getAuthStateManager","getTranslationService","getOAuthConfigStorage","isOAuthConfigured","getAuthenticationMode","isOAuthAuthenticated","getAuthenticationStatus","isAuthenticated","requiresAuthentication","refreshConfiguration","isTranslating","translateDocumentAction","hasDraft","draft","hasPublished","published","onComplete","apiVersion","action","label","onHandle","contentExtractor","documentCreationService","localeService","serviceManager","authState","enabledLocales","documentContent","collisionConfig","selectedLocalesResult","creationResults","successCount","failCount","r","collisionHandlings","slugFallbackNote","f","collisionNote","successIds","BulkTranslateTool","isProcessing","isLoadingDocuments","availableDocuments","selectedTypes","selectedDocumentIds","expandedTypes","processingStatus","currentProcessingIndex","createDocuments","documentCreationResult","fetchDocuments","prev","documentsByType","handleTypeSelection","selected","newSelectedTypes","newSelectedDocumentIds","newSelectedDocuments","values","flat","getDocumentTitle","handleDocumentSelection","typeDocuments","handleTypeExpansion","newExpandedTypes","handleSelectAll","allTypes","allDocuments","allDocumentIds","handleClearSelection","handleBulkTranslate","shouldCreateDocuments","validContents","hasContent","successfulResponses","successfulDocuments","responseIndex","_","sort","a","localeCompare","isExpanded","selectedInType","isPartiallySelected","isFullySelected","indeterminate","minWidth","marginLeft","textAlign","height","backgroundColor","borderRadius","overflow","transition","bulkTranslateTool","component","manageDNTFieldsAction","handleManageDNT","extractFields","parentPath","dntFields","fieldList","PasswordInput","elementProps","handleChange","nextValue","DNTFieldBadge","fieldTitle","setIsDNT","isLoading","setIsLoading","loadDNTStatus","handleToggle","tooltipContent","direction","fontWeight","placement","minHeight","withDNTBadge","Component","fieldProps","typedProps","schemaType","DNTFieldInput","handleToggleDNT","paddingTop","NON_TRANSLATABLE_TYPES","isNonTranslatableType","matchesDNTFieldNamePattern","matches","lowerName","matchesDNTGroupPattern","groupOrFieldsetName","nameMatch","groupMatch","fieldsetMatch","shouldShowDNTBadge","getDNTDebugInfo","storedDNT","defaultResult","DebugDNTBadge","jsonType","setStoredDNT","fieldContext","allFields","effectiveDNT","willBeInPayload","badgeColor","statusText","debugLines","line","portal","PluginConfigContext","usePluginConfig","legacyOAuthConfigSchema","StudioLayout","setIsInitialized","oauthServiceManager","debugModeEnabled","initializeServices","subscription","unsubscribe","FieldWrapper","fieldset","blacklistedFieldNames","isBlacklistedName","isTranslatableType","shouldShowInteractiveDNT","studio","actions","newActions","form","tools","newTools","schema"],"sourceRoot":""}