@easyling/sanity-connector 0.0.1 → 0.0.2-rc.1

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 (242) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/package.json +18 -12
  3. package/dist/actions/bulkTranslate.d.ts +0 -7
  4. package/dist/actions/bulkTranslate.d.ts.map +0 -1
  5. package/dist/actions/bulkTranslate.js +0 -543
  6. package/dist/actions/bulkTranslate.js.map +0 -1
  7. package/dist/actions/manageDNTFields.d.ts +0 -12
  8. package/dist/actions/manageDNTFields.d.ts.map +0 -1
  9. package/dist/actions/manageDNTFields.js +0 -100
  10. package/dist/actions/manageDNTFields.js.map +0 -1
  11. package/dist/actions/translateDocument.d.ts +0 -7
  12. package/dist/actions/translateDocument.d.ts.map +0 -1
  13. package/dist/actions/translateDocument.js +0 -256
  14. package/dist/actions/translateDocument.js.map +0 -1
  15. package/dist/components/RadioWithDefault.d.ts +0 -17
  16. package/dist/components/RadioWithDefault.d.ts.map +0 -1
  17. package/dist/components/RadioWithDefault.js +0 -29
  18. package/dist/components/RadioWithDefault.js.map +0 -1
  19. package/dist/components/auth/AuthNavbar.d.ts +0 -18
  20. package/dist/components/auth/AuthNavbar.d.ts.map +0 -1
  21. package/dist/components/auth/AuthNavbar.js +0 -15
  22. package/dist/components/auth/AuthNavbar.js.map +0 -1
  23. package/dist/components/auth/AuthStatus.d.ts +0 -27
  24. package/dist/components/auth/AuthStatus.d.ts.map +0 -1
  25. package/dist/components/auth/AuthStatus.js +0 -82
  26. package/dist/components/auth/AuthStatus.js.map +0 -1
  27. package/dist/components/auth/AuthStatusWrapper.d.ts +0 -15
  28. package/dist/components/auth/AuthStatusWrapper.d.ts.map +0 -1
  29. package/dist/components/auth/AuthStatusWrapper.js +0 -39
  30. package/dist/components/auth/AuthStatusWrapper.js.map +0 -1
  31. package/dist/components/auth/MigrationPrompt.d.ts +0 -20
  32. package/dist/components/auth/MigrationPrompt.d.ts.map +0 -1
  33. package/dist/components/auth/MigrationPrompt.js +0 -16
  34. package/dist/components/auth/MigrationPrompt.js.map +0 -1
  35. package/dist/components/auth/MigrationPromptWrapper.d.ts +0 -14
  36. package/dist/components/auth/MigrationPromptWrapper.d.ts.map +0 -1
  37. package/dist/components/auth/MigrationPromptWrapper.js +0 -16
  38. package/dist/components/auth/MigrationPromptWrapper.js.map +0 -1
  39. package/dist/components/auth/OAuthCallback.d.ts +0 -20
  40. package/dist/components/auth/OAuthCallback.d.ts.map +0 -1
  41. package/dist/components/auth/OAuthCallback.js +0 -12
  42. package/dist/components/auth/OAuthCallback.js.map +0 -1
  43. package/dist/components/auth/index.d.ts +0 -15
  44. package/dist/components/auth/index.d.ts.map +0 -1
  45. package/dist/components/auth/index.js +0 -12
  46. package/dist/components/auth/index.js.map +0 -1
  47. package/dist/components/config/LocaleConfigTool.d.ts +0 -17
  48. package/dist/components/config/LocaleConfigTool.d.ts.map +0 -1
  49. package/dist/components/config/LocaleConfigTool.js +0 -186
  50. package/dist/components/config/LocaleConfigTool.js.map +0 -1
  51. package/dist/components/config/LocaleConfigToolWrapper.d.ts +0 -13
  52. package/dist/components/config/LocaleConfigToolWrapper.d.ts.map +0 -1
  53. package/dist/components/config/LocaleConfigToolWrapper.js +0 -26
  54. package/dist/components/config/LocaleConfigToolWrapper.js.map +0 -1
  55. package/dist/components/config/OAuthConfig.d.ts +0 -26
  56. package/dist/components/config/OAuthConfig.d.ts.map +0 -1
  57. package/dist/components/config/OAuthConfig.js +0 -152
  58. package/dist/components/config/OAuthConfig.js.map +0 -1
  59. package/dist/components/config/OAuthConfigWrapper.d.ts +0 -13
  60. package/dist/components/config/OAuthConfigWrapper.d.ts.map +0 -1
  61. package/dist/components/config/OAuthConfigWrapper.js +0 -41
  62. package/dist/components/config/OAuthConfigWrapper.js.map +0 -1
  63. package/dist/components/config/PasswordInput.d.ts +0 -14
  64. package/dist/components/config/PasswordInput.d.ts.map +0 -1
  65. package/dist/components/config/PasswordInput.js +0 -23
  66. package/dist/components/config/PasswordInput.js.map +0 -1
  67. package/dist/components/config/index.d.ts +0 -9
  68. package/dist/components/config/index.d.ts.map +0 -1
  69. package/dist/components/config/index.js +0 -8
  70. package/dist/components/config/index.js.map +0 -1
  71. package/dist/components/config/localeConfigToolDefinition.d.ts +0 -13
  72. package/dist/components/config/localeConfigToolDefinition.d.ts.map +0 -1
  73. package/dist/components/config/localeConfigToolDefinition.js +0 -19
  74. package/dist/components/config/localeConfigToolDefinition.js.map +0 -1
  75. package/dist/components/config/oauthConfigToolDefinition.d.ts +0 -13
  76. package/dist/components/config/oauthConfigToolDefinition.d.ts.map +0 -1
  77. package/dist/components/config/oauthConfigToolDefinition.js +0 -19
  78. package/dist/components/config/oauthConfigToolDefinition.js.map +0 -1
  79. package/dist/components/dialogs/ConfirmationDialog.d.ts +0 -21
  80. package/dist/components/dialogs/ConfirmationDialog.d.ts.map +0 -1
  81. package/dist/components/dialogs/ConfirmationDialog.js +0 -28
  82. package/dist/components/dialogs/ConfirmationDialog.js.map +0 -1
  83. package/dist/components/dialogs/ErrorDialog.d.ts +0 -21
  84. package/dist/components/dialogs/ErrorDialog.d.ts.map +0 -1
  85. package/dist/components/dialogs/ErrorDialog.js +0 -28
  86. package/dist/components/dialogs/ErrorDialog.js.map +0 -1
  87. package/dist/components/dialogs/LocaleSelectionDialog.d.ts +0 -41
  88. package/dist/components/dialogs/LocaleSelectionDialog.d.ts.map +0 -1
  89. package/dist/components/dialogs/LocaleSelectionDialog.js +0 -117
  90. package/dist/components/dialogs/LocaleSelectionDialog.js.map +0 -1
  91. package/dist/components/dialogs/SuccessDialog.d.ts +0 -19
  92. package/dist/components/dialogs/SuccessDialog.d.ts.map +0 -1
  93. package/dist/components/dialogs/SuccessDialog.js +0 -37
  94. package/dist/components/dialogs/SuccessDialog.js.map +0 -1
  95. package/dist/components/dialogs/index.d.ts +0 -12
  96. package/dist/components/dialogs/index.d.ts.map +0 -1
  97. package/dist/components/dialogs/index.js +0 -8
  98. package/dist/components/dialogs/index.js.map +0 -1
  99. package/dist/components/dnt/DNTFieldBadge.d.ts +0 -16
  100. package/dist/components/dnt/DNTFieldBadge.d.ts.map +0 -1
  101. package/dist/components/dnt/DNTFieldBadge.js +0 -56
  102. package/dist/components/dnt/DNTFieldBadge.js.map +0 -1
  103. package/dist/components/dnt/DNTFieldComponent.d.ts +0 -17
  104. package/dist/components/dnt/DNTFieldComponent.d.ts.map +0 -1
  105. package/dist/components/dnt/DNTFieldComponent.js +0 -21
  106. package/dist/components/dnt/DNTFieldComponent.js.map +0 -1
  107. package/dist/components/dnt/DNTFieldInput.d.ts +0 -14
  108. package/dist/components/dnt/DNTFieldInput.d.ts.map +0 -1
  109. package/dist/components/dnt/DNTFieldInput.js +0 -76
  110. package/dist/components/dnt/DNTFieldInput.js.map +0 -1
  111. package/dist/components/dnt/index.d.ts +0 -7
  112. package/dist/components/dnt/index.d.ts.map +0 -1
  113. package/dist/components/dnt/index.js +0 -7
  114. package/dist/components/dnt/index.js.map +0 -1
  115. package/dist/config/index.d.ts +0 -6
  116. package/dist/config/index.d.ts.map +0 -1
  117. package/dist/config/index.js +0 -6
  118. package/dist/config/index.js.map +0 -1
  119. package/dist/config/pluginConfig.d.ts +0 -163
  120. package/dist/config/pluginConfig.d.ts.map +0 -1
  121. package/dist/config/pluginConfig.js +0 -548
  122. package/dist/config/pluginConfig.js.map +0 -1
  123. package/dist/index.d.ts +0 -12
  124. package/dist/index.d.ts.map +0 -1
  125. package/dist/index.js +0 -12
  126. package/dist/index.js.map +0 -1
  127. package/dist/plugin.d.ts +0 -3
  128. package/dist/plugin.d.ts.map +0 -1
  129. package/dist/plugin.js +0 -137
  130. package/dist/plugin.js.map +0 -1
  131. package/dist/services/authStateManager.d.ts +0 -94
  132. package/dist/services/authStateManager.d.ts.map +0 -1
  133. package/dist/services/authStateManager.js +0 -208
  134. package/dist/services/authStateManager.js.map +0 -1
  135. package/dist/services/contentExtractor.d.ts +0 -95
  136. package/dist/services/contentExtractor.d.ts.map +0 -1
  137. package/dist/services/contentExtractor.js +0 -516
  138. package/dist/services/contentExtractor.js.map +0 -1
  139. package/dist/services/dialogService.d.ts +0 -96
  140. package/dist/services/dialogService.d.ts.map +0 -1
  141. package/dist/services/dialogService.js +0 -244
  142. package/dist/services/dialogService.js.map +0 -1
  143. package/dist/services/dntServiceManager.d.ts +0 -44
  144. package/dist/services/dntServiceManager.d.ts.map +0 -1
  145. package/dist/services/dntServiceManager.js +0 -74
  146. package/dist/services/dntServiceManager.js.map +0 -1
  147. package/dist/services/dntStorageAdapter.d.ts +0 -73
  148. package/dist/services/dntStorageAdapter.d.ts.map +0 -1
  149. package/dist/services/dntStorageAdapter.js +0 -192
  150. package/dist/services/dntStorageAdapter.js.map +0 -1
  151. package/dist/services/documentCreationService.d.ts +0 -139
  152. package/dist/services/documentCreationService.d.ts.map +0 -1
  153. package/dist/services/documentCreationService.js +0 -938
  154. package/dist/services/documentCreationService.js.map +0 -1
  155. package/dist/services/localeService.d.ts +0 -160
  156. package/dist/services/localeService.d.ts.map +0 -1
  157. package/dist/services/localeService.js +0 -300
  158. package/dist/services/localeService.js.map +0 -1
  159. package/dist/services/localeStorageAdapter.d.ts +0 -42
  160. package/dist/services/localeStorageAdapter.d.ts.map +0 -1
  161. package/dist/services/localeStorageAdapter.js +0 -107
  162. package/dist/services/localeStorageAdapter.js.map +0 -1
  163. package/dist/services/oauthConfigStorage.d.ts +0 -46
  164. package/dist/services/oauthConfigStorage.d.ts.map +0 -1
  165. package/dist/services/oauthConfigStorage.js +0 -122
  166. package/dist/services/oauthConfigStorage.js.map +0 -1
  167. package/dist/services/oauthService.d.ts +0 -48
  168. package/dist/services/oauthService.d.ts.map +0 -1
  169. package/dist/services/oauthService.js +0 -71
  170. package/dist/services/oauthService.js.map +0 -1
  171. package/dist/services/oauthServiceManager.d.ts +0 -189
  172. package/dist/services/oauthServiceManager.d.ts.map +0 -1
  173. package/dist/services/oauthServiceManager.js +0 -380
  174. package/dist/services/oauthServiceManager.js.map +0 -1
  175. package/dist/services/tokenStorage.d.ts +0 -54
  176. package/dist/services/tokenStorage.d.ts.map +0 -1
  177. package/dist/services/tokenStorage.js +0 -140
  178. package/dist/services/tokenStorage.js.map +0 -1
  179. package/dist/services/translationService.d.ts +0 -374
  180. package/dist/services/translationService.d.ts.map +0 -1
  181. package/dist/services/translationService.js +0 -687
  182. package/dist/services/translationService.js.map +0 -1
  183. package/dist/services/unifiedConfigStorage.d.ts +0 -124
  184. package/dist/services/unifiedConfigStorage.d.ts.map +0 -1
  185. package/dist/services/unifiedConfigStorage.js +0 -304
  186. package/dist/services/unifiedConfigStorage.js.map +0 -1
  187. package/dist/test-utils.d.ts +0 -9
  188. package/dist/test-utils.d.ts.map +0 -1
  189. package/dist/test-utils.js +0 -13
  190. package/dist/test-utils.js.map +0 -1
  191. package/dist/types/dialog.d.ts +0 -107
  192. package/dist/types/dialog.d.ts.map +0 -1
  193. package/dist/types/dialog.js +0 -6
  194. package/dist/types/dialog.js.map +0 -1
  195. package/dist/types/dnt.d.ts +0 -84
  196. package/dist/types/dnt.d.ts.map +0 -1
  197. package/dist/types/dnt.js +0 -5
  198. package/dist/types/dnt.js.map +0 -1
  199. package/dist/types/index.d.ts +0 -12
  200. package/dist/types/index.d.ts.map +0 -1
  201. package/dist/types/index.js +0 -6
  202. package/dist/types/index.js.map +0 -1
  203. package/dist/types/locale.d.ts +0 -116
  204. package/dist/types/locale.d.ts.map +0 -1
  205. package/dist/types/locale.js +0 -189
  206. package/dist/types/locale.js.map +0 -1
  207. package/dist/types/oauth.d.ts +0 -90
  208. package/dist/types/oauth.d.ts.map +0 -1
  209. package/dist/types/oauth.js +0 -62
  210. package/dist/types/oauth.js.map +0 -1
  211. package/dist/types/pluginConfig.d.ts +0 -45
  212. package/dist/types/pluginConfig.d.ts.map +0 -1
  213. package/dist/types/pluginConfig.js +0 -6
  214. package/dist/types/pluginConfig.js.map +0 -1
  215. package/dist/types/translation.d.ts +0 -122
  216. package/dist/types/translation.d.ts.map +0 -1
  217. package/dist/types/translation.js +0 -6
  218. package/dist/types/translation.js.map +0 -1
  219. package/dist/utils/htmlFormatter.d.ts +0 -66
  220. package/dist/utils/htmlFormatter.d.ts.map +0 -1
  221. package/dist/utils/htmlFormatter.js +0 -191
  222. package/dist/utils/htmlFormatter.js.map +0 -1
  223. package/dist/utils/index.d.ts +0 -15
  224. package/dist/utils/index.d.ts.map +0 -1
  225. package/dist/utils/index.js +0 -16
  226. package/dist/utils/index.js.map +0 -1
  227. package/dist/utils/logger.d.ts +0 -105
  228. package/dist/utils/logger.d.ts.map +0 -1
  229. package/dist/utils/logger.js +0 -229
  230. package/dist/utils/logger.js.map +0 -1
  231. package/dist/utils/oauthErrorFeedback.d.ts +0 -76
  232. package/dist/utils/oauthErrorFeedback.d.ts.map +0 -1
  233. package/dist/utils/oauthErrorFeedback.js +0 -134
  234. package/dist/utils/oauthErrorFeedback.js.map +0 -1
  235. package/dist/utils/oauthLogger.d.ts +0 -176
  236. package/dist/utils/oauthLogger.d.ts.map +0 -1
  237. package/dist/utils/oauthLogger.js +0 -282
  238. package/dist/utils/oauthLogger.js.map +0 -1
  239. package/dist/utils/validator.d.ts +0 -67
  240. package/dist/utils/validator.d.ts.map +0 -1
  241. package/dist/utils/validator.js +0 -390
  242. package/dist/utils/validator.js.map +0 -1
@@ -1,687 +0,0 @@
1
- import * as TranslationRequestProto from '@easyling/sanity/dist/generated/translation_request';
2
- import * as TranslationResponseProto from '@easyling/sanity/dist/generated/translation_response';
3
- export class TranslationService {
4
- constructor(placeholderEndpoint = 'http://localhost:8275/translate', requestContentType = 'application/json', responseAcceptHeader = 'application/json') {
5
- this.placeholderEndpoint = placeholderEndpoint;
6
- this.requestContentType = requestContentType;
7
- this.responseAcceptHeader = responseAcceptHeader;
8
- }
9
- /**
10
- * Infer the Sanity field type from a value
11
- *
12
- * @param value - The field value to inspect
13
- * @returns The inferred Sanity type string
14
- */
15
- inferSanityType(value) {
16
- if (value === null || value === undefined) {
17
- return 'undefined';
18
- }
19
- // Check for Sanity-specific object types
20
- if (typeof value === 'object' && !Array.isArray(value)) {
21
- const obj = value;
22
- // Sanity objects have a _type field
23
- if (obj._type) {
24
- return obj._type;
25
- }
26
- }
27
- // Check primitive types
28
- if (typeof value === 'string') {
29
- return 'string';
30
- }
31
- if (typeof value === 'number') {
32
- return 'number';
33
- }
34
- if (typeof value === 'boolean') {
35
- return 'boolean';
36
- }
37
- if (Array.isArray(value)) {
38
- return 'array';
39
- }
40
- if (typeof value === 'object') {
41
- return 'object';
42
- }
43
- return 'unknown';
44
- }
45
- /**
46
- * Set authentication token and project ID
47
- * Requirements: 4.1, 4.2, 4.3
48
- *
49
- * @param token - Access token for API authentication
50
- * @param projectId - Project ID to include in requests
51
- */
52
- setAuthToken(token, projectId) {
53
- this.accessToken = token;
54
- this.projectId = projectId;
55
- }
56
- /**
57
- * Clear authentication data
58
- */
59
- clearAuth() {
60
- this.accessToken = undefined;
61
- this.projectId = undefined;
62
- }
63
- /**
64
- * Update configuration for content types and endpoint
65
- * Allows partial updates - only provided parameters will be updated
66
- * Requirements: 1.1, 2.3, 3.3
67
- *
68
- * @param endpoint - Optional translation API endpoint URL
69
- * @param requestContentType - Optional request Content-Type header value
70
- * @param responseAcceptHeader - Optional response Accept header value
71
- */
72
- setConfiguration(endpoint, requestContentType, responseAcceptHeader) {
73
- if (endpoint !== undefined) {
74
- this.placeholderEndpoint = endpoint;
75
- }
76
- if (requestContentType !== undefined) {
77
- this.requestContentType = requestContentType;
78
- }
79
- if (responseAcceptHeader !== undefined) {
80
- this.responseAcceptHeader = responseAcceptHeader;
81
- }
82
- }
83
- /**
84
- * Convert internal payload to Protocol Buffer binary format
85
- * Requirements: Uses @easyling/sanity protobuf library
86
- *
87
- * @param payload - Internal translation request payload
88
- * @returns Binary protobuf message
89
- */
90
- convertPayloadToProtobuf(payload) {
91
- // Convert internal TranslatableField objects to protobuf format
92
- // Type information should be set by this point (from contentExtractor)
93
- const protoFields = {};
94
- for (const [key, field] of Object.entries(payload.content.fields)) {
95
- // Handle both TranslatableField objects and plain values (for backward compatibility)
96
- if (field && typeof field === 'object' && 'value' in field) {
97
- // Already a TranslatableField object - type should be set from contentExtractor
98
- const typedField = field;
99
- // Warn if type is missing - should be set by contentExtractor in normal flow
100
- let fieldType = typedField.type;
101
- if (!fieldType) {
102
- console.warn(`Field '${key}' missing type in protobuf conversion, inferring from value`);
103
- fieldType = this.inferSanityType(typedField.value);
104
- }
105
- protoFields[key] = {
106
- value: typeof typedField.value === 'string' ? typedField.value : JSON.stringify(typedField.value),
107
- dnt: typedField.dnt || false,
108
- type: fieldType
109
- };
110
- }
111
- else {
112
- // Plain value - may happen for direct API calls that bypass contentExtractor
113
- console.warn(`Field '${key}' not in TranslatableField format, wrapping with inferred type`);
114
- protoFields[key] = {
115
- value: typeof field === 'string' ? field : JSON.stringify(field),
116
- dnt: false,
117
- type: this.inferSanityType(field)
118
- };
119
- }
120
- }
121
- // Create protobuf message from our payload
122
- const protoPayload = TranslationRequestProto.TranslationRequestPayload.create({
123
- content: {
124
- body: payload.content.body,
125
- title: payload.content.title,
126
- slug: payload.content.slug,
127
- fields: protoFields
128
- },
129
- project: this.projectId || '', // Project code for identification
130
- format: payload.format,
131
- metadata: {
132
- documentId: payload.metadata.documentId,
133
- documentType: payload.metadata.documentType,
134
- title: payload.metadata.title,
135
- sourceLanguage: payload.metadata.sourceLanguage || '',
136
- targetLanguage: payload.metadata.targetLanguage || '',
137
- targetLocales: payload.metadata.targetLocales || []
138
- }
139
- });
140
- // Encode protobuf message to binary format
141
- return TranslationRequestProto.TranslationRequestPayload.encode(protoPayload).finish();
142
- }
143
- /**
144
- * Convert protobuf payload to JSON for logging purposes only
145
- *
146
- * @param payload - Internal translation request payload
147
- * @returns JSON representation for logging
148
- */
149
- convertPayloadToProtobufJSON(payload) {
150
- // Convert internal TranslatableField objects to protobuf format
151
- const protoFields = {};
152
- for (const [key, field] of Object.entries(payload.content.fields)) {
153
- if (field && typeof field === 'object' && 'value' in field) {
154
- const typedField = field;
155
- protoFields[key] = {
156
- value: typeof typedField.value === 'string' ? typedField.value : JSON.stringify(typedField.value),
157
- dnt: typedField.dnt || false,
158
- type: typedField.type || 'unknown'
159
- };
160
- }
161
- else {
162
- protoFields[key] = {
163
- value: typeof field === 'string' ? field : JSON.stringify(field),
164
- dnt: false,
165
- type: 'unknown'
166
- };
167
- }
168
- }
169
- const protoPayload = TranslationRequestProto.TranslationRequestPayload.create({
170
- content: {
171
- body: payload.content.body,
172
- title: payload.content.title,
173
- slug: payload.content.slug,
174
- fields: protoFields
175
- },
176
- project: this.projectId || '',
177
- format: payload.format,
178
- metadata: {
179
- documentId: payload.metadata.documentId,
180
- documentType: payload.metadata.documentType,
181
- title: payload.metadata.title,
182
- sourceLanguage: payload.metadata.sourceLanguage || '',
183
- targetLanguage: payload.metadata.targetLanguage || '',
184
- targetLocales: payload.metadata.targetLocales || []
185
- }
186
- });
187
- return TranslationRequestProto.TranslationRequestPayload.toJSON(protoPayload);
188
- }
189
- /**
190
- * Normalize field values to ensure consistency
191
- * Extracts values from TranslatableField objects and handles various formats
192
- */
193
- normalizeTranslatedFields(fields) {
194
- const normalizedFields = {};
195
- if (!fields || typeof fields !== 'object') {
196
- return normalizedFields;
197
- }
198
- for (const [key, fieldValue] of Object.entries(fields)) {
199
- // Handle both TranslatableField objects and plain values
200
- if (fieldValue && typeof fieldValue === 'object' && 'value' in fieldValue) {
201
- // It's already a TranslatableField object
202
- normalizedFields[key] = {
203
- value: fieldValue.value,
204
- dnt: fieldValue.dnt || false,
205
- type: fieldValue.type || this.inferSanityType(fieldValue.value)
206
- };
207
- }
208
- else {
209
- // It's a plain value - wrap it in TranslatableField format
210
- normalizedFields[key] = {
211
- value: fieldValue,
212
- dnt: false,
213
- type: this.inferSanityType(fieldValue)
214
- };
215
- }
216
- }
217
- return normalizedFields;
218
- }
219
- /**
220
- * Convert binary protobuf response to internal format
221
- * Requirements: Uses @easyling/sanity protobuf library
222
- *
223
- * @param binaryData - Binary protobuf response data
224
- * @returns Internal translation response format
225
- */
226
- convertProtobufBinaryToResponse(binaryData) {
227
- // Decode binary protobuf response
228
- const protoResponse = TranslationResponseProto.TranslationResponse.decode(binaryData);
229
- // Convert to internal format
230
- const translatedDocuments = protoResponse.translatedDocuments.map(doc => {
231
- // Convert protobuf TranslatableField back to internal format
232
- const fields = {};
233
- if (doc.fields && typeof doc.fields === 'object') {
234
- for (const [key, protoField] of Object.entries(doc.fields)) {
235
- if (protoField && typeof protoField === 'object' && 'value' in protoField) {
236
- const fieldValue = protoField.value;
237
- const fieldType = protoField.type;
238
- try {
239
- // Try to parse as JSON if it's a stringified value
240
- const parsedValue = JSON.parse(fieldValue);
241
- fields[key] = {
242
- value: parsedValue,
243
- dnt: protoField.dnt || false,
244
- type: fieldType || this.inferSanityType(parsedValue)
245
- };
246
- }
247
- catch {
248
- // If parsing fails, use the string value as-is
249
- fields[key] = {
250
- value: fieldValue,
251
- dnt: protoField.dnt || false,
252
- type: fieldType || this.inferSanityType(fieldValue)
253
- };
254
- }
255
- }
256
- }
257
- }
258
- return {
259
- body: doc.body,
260
- title: doc.title,
261
- slug: doc.slug,
262
- fields,
263
- locale: doc.locale
264
- };
265
- });
266
- return {
267
- success: protoResponse.success,
268
- translatedDocuments,
269
- sourceLocale: protoResponse.sourceLocale,
270
- error: protoResponse.error,
271
- requestId: protoResponse.requestId
272
- };
273
- }
274
- /**
275
- * Convert protobuf JSON response back to internal format (for legacy support)
276
- * Requirements: Uses @easyling/sanity protobuf library
277
- *
278
- * @param jsonData - JSON response data
279
- * @returns Internal translation response format
280
- */
281
- convertProtobufJSONToResponse(jsonData) {
282
- // Parse the JSON into a protobuf message
283
- const protoResponse = TranslationResponseProto.TranslationResponse.fromJSON(jsonData);
284
- // Convert to internal format
285
- const translatedDocuments = protoResponse.translatedDocuments.map((doc, index) => {
286
- // Get original document data from jsonData to handle mixed field formats
287
- const originalDoc = jsonData.translatedDocuments?.[index];
288
- // Convert protobuf TranslatableField back to internal format
289
- const protoFields = {};
290
- if (doc.fields && typeof doc.fields === 'object') {
291
- for (const [key, protoField] of Object.entries(doc.fields)) {
292
- // Get the original value from jsonData to check if protobuf lost it
293
- const originalValue = originalDoc?.fields?.[key];
294
- // Handle protobuf field format
295
- if (protoField && typeof protoField === 'object' && 'value' in protoField) {
296
- const fieldValue = protoField.value;
297
- const fieldType = protoField.type;
298
- // Check if protobuf parsing lost the value (empty string when original had value)
299
- if ((fieldValue === '' || fieldValue === undefined) && originalValue !== undefined && originalValue !== '') {
300
- // Use original value instead
301
- protoFields[key] = originalValue;
302
- }
303
- else {
304
- try {
305
- // Try to parse as JSON if it's a stringified value
306
- const parsedValue = JSON.parse(fieldValue);
307
- protoFields[key] = {
308
- value: parsedValue,
309
- dnt: protoField.dnt || false,
310
- type: fieldType || this.inferSanityType(parsedValue)
311
- };
312
- }
313
- catch {
314
- // If parsing fails, use the string value as-is
315
- protoFields[key] = {
316
- value: fieldValue,
317
- dnt: protoField.dnt || false,
318
- type: fieldType || this.inferSanityType(fieldValue)
319
- };
320
- }
321
- }
322
- }
323
- else {
324
- // Plain value - but protobuf parsing might have lost it
325
- // Fall back to original JSON data if the value is empty/undefined
326
- if (originalValue !== undefined && (!protoField || protoField === '')) {
327
- protoFields[key] = originalValue;
328
- }
329
- else {
330
- protoFields[key] = protoField;
331
- }
332
- }
333
- }
334
- }
335
- // Also check for fields in original data that might have been lost in protobuf conversion
336
- if (originalDoc?.fields && typeof originalDoc.fields === 'object') {
337
- for (const [key, originalValue] of Object.entries(originalDoc.fields)) {
338
- if (!(key in protoFields)) {
339
- protoFields[key] = originalValue;
340
- }
341
- }
342
- }
343
- // Normalize the fields to ensure consistent format
344
- const fields = this.normalizeTranslatedFields(protoFields);
345
- return {
346
- body: doc.body,
347
- title: doc.title,
348
- slug: doc.slug,
349
- fields,
350
- locale: doc.locale
351
- };
352
- });
353
- return {
354
- success: protoResponse.success,
355
- translatedDocuments,
356
- sourceLocale: protoResponse.sourceLocale,
357
- error: protoResponse.error,
358
- requestId: protoResponse.requestId
359
- };
360
- }
361
- /**
362
- * Prepare a translation request for a single document
363
- * Requirements: 1.2, 1.3, 3.3, 2.5, 2.7
364
- *
365
- * @param content - Document content to translate
366
- * @param documentType - Type of the document
367
- * @param sourceLanguage - Source language code (optional)
368
- * @param targetLanguage - Single target language code (optional, for backward compatibility)
369
- * @param targetLocales - Array of target locale codes (optional, for multi-locale support)
370
- */
371
- prepareTranslationRequest(content, documentType = 'document', sourceLanguage, targetLanguage, targetLocales) {
372
- if (!content || !content.documentId || !content.htmlContent) {
373
- throw new Error('Invalid document content provided');
374
- }
375
- // Convert flat fields to TranslatableField objects and ensure type is ALWAYS set
376
- const translatableFields = {};
377
- if (content.fields) {
378
- for (const [key, value] of Object.entries(content.fields)) {
379
- // If the field is already in the new format, ensure type is set
380
- if (value && typeof value === 'object' && 'value' in value) {
381
- const typedField = value;
382
- // Type should already be set from contentExtractor, but ensure it's never undefined
383
- if (!typedField.type) {
384
- console.warn(`Field '${key}' missing type, inferring from value`);
385
- }
386
- translatableFields[key] = {
387
- ...typedField,
388
- type: typedField.type || this.inferSanityType(typedField.value)
389
- };
390
- }
391
- else {
392
- // Convert flat field to TranslatableField object (should rarely happen)
393
- console.warn(`Field '${key}' not in TranslatableField format, converting`);
394
- translatableFields[key] = {
395
- value,
396
- dnt: false,
397
- type: this.inferSanityType(value)
398
- };
399
- }
400
- }
401
- }
402
- const payload = {
403
- content: {
404
- body: content.htmlContent,
405
- title: content.title || `Document ${content.documentId}`,
406
- slug: content.slug || '',
407
- fields: translatableFields
408
- },
409
- format: 'html',
410
- metadata: {
411
- documentId: content.documentId,
412
- documentType,
413
- title: content.title || `Document ${content.documentId}`,
414
- ...(sourceLanguage && { sourceLanguage }),
415
- // Support both single targetLanguage (backward compatibility) and targetLocales array
416
- ...(targetLanguage && { targetLanguage }),
417
- ...(targetLocales && targetLocales.length > 0 && { targetLocales })
418
- }
419
- };
420
- return {
421
- documentId: content.documentId,
422
- endpoint: this.placeholderEndpoint,
423
- payload
424
- };
425
- }
426
- /**
427
- * Translate a single document
428
- * Requirements: 1.2, 1.3, 3.3, 2.5, 2.7
429
- *
430
- * @param content - Document content to translate
431
- * @param documentType - Type of the document
432
- * @param sourceLanguage - Source language code (optional)
433
- * @param targetLanguage - Single target language code (optional, for backward compatibility)
434
- * @param targetLocales - Array of target locale codes (optional, for multi-locale support)
435
- */
436
- async translateDocument(content, documentType = 'document', sourceLanguage, targetLanguage, targetLocales) {
437
- const request = this.prepareTranslationRequest(content, documentType, sourceLanguage, targetLanguage, targetLocales);
438
- return this.sendTranslationRequest(request);
439
- }
440
- /**
441
- * Send translation request to the configured endpoint
442
- *
443
- * Uses the @easyling/sanity Protocol Buffer library to format messages as JSON
444
- * (not binary protobuf) for better compatibility with various backends.
445
- * Handles the new array-based response format with backward compatibility.
446
- * The service now expects translatedDocuments as an array, but will convert
447
- * legacy formats (translatedContent or translations object) to the new format.
448
- *
449
- * Supports dual mode operation:
450
- * - Authenticated mode: Uses Bearer token authentication when configured
451
- * - Legacy mode: Works without authentication for backward compatibility
452
- */
453
- async sendTranslationRequest(request) {
454
- try {
455
- this.logTranslationRequest(request);
456
- // Build headers with configured content types
457
- // Requirements: 2.2, 2.3, 3.2, 3.3
458
- const headers = {
459
- 'Content-Type': this.requestContentType,
460
- 'Accept': this.responseAcceptHeader
461
- };
462
- // Add Authorization header if access token is available
463
- if (this.accessToken) {
464
- headers['Authorization'] = `Bearer ${this.accessToken}`;
465
- }
466
- // Serialize payload based on configured content type
467
- // Requirements: 2.2, 2.3
468
- let body;
469
- if (this.requestContentType === 'application/x-protobuf') {
470
- // Use binary protobuf serialization
471
- body = this.convertPayloadToProtobuf(request.payload);
472
- }
473
- else {
474
- // Use JSON serialization (protobuf JSON format)
475
- const protobufJSON = this.convertPayloadToProtobufJSON(request.payload);
476
- body = JSON.stringify(protobufJSON);
477
- }
478
- const response = await fetch(request.endpoint, {
479
- method: 'POST',
480
- headers,
481
- body: body // TypeScript fetch types are strict, but Uint8Array is valid
482
- });
483
- if (!response.ok) {
484
- // Handle 401 Unauthorized
485
- if (response.status === 401) {
486
- return {
487
- success: false,
488
- error: 'Authentication failed. Please check your access token in the Easyling Configuration.'
489
- };
490
- }
491
- throw new Error(`HTTP error! status: ${response.status}`);
492
- }
493
- // Parse response based on configured Accept header
494
- // Requirements: 3.2, 3.3, 3.5
495
- if (this.responseAcceptHeader === 'application/x-protobuf') {
496
- // Parse binary protobuf response
497
- const arrayBuffer = await response.arrayBuffer();
498
- const binaryData = new Uint8Array(arrayBuffer);
499
- return this.convertProtobufBinaryToResponse(binaryData);
500
- }
501
- // Parse JSON response
502
- const data = await response.json();
503
- // Try to parse as protobuf JSON format first
504
- try {
505
- // If the response has the expected protobuf structure, parse it
506
- if (data.success !== undefined && (data.translatedDocuments || data.error)) {
507
- return this.convertProtobufJSONToResponse(data);
508
- }
509
- }
510
- catch (protoError) {
511
- console.warn('Failed to parse response as protobuf format, falling back to legacy handling:', protoError);
512
- }
513
- // New format: translatedDocuments array (without success field - for backward compatibility)
514
- if (data.translatedDocuments && Array.isArray(data.translatedDocuments)) {
515
- // Normalize fields in each translated document to ensure consistency
516
- const normalizedDocuments = data.translatedDocuments.map((doc) => ({
517
- ...doc,
518
- fields: this.normalizeTranslatedFields(doc.fields || {})
519
- }));
520
- return {
521
- success: true,
522
- translatedDocuments: normalizedDocuments,
523
- sourceLocale: data.sourceLocale,
524
- requestId: data.requestId
525
- };
526
- }
527
- // Backward compatibility: translations object (convert to array)
528
- if (data.translations) {
529
- const translatedDocuments = [];
530
- for (const [locale, translation] of Object.entries(data.translations)) {
531
- if (translation && typeof translation === 'object' && 'content' in translation) {
532
- const content = translation.content;
533
- // Normalize fields to ensure consistency
534
- translatedDocuments.push({
535
- ...content,
536
- fields: this.normalizeTranslatedFields(content.fields || {}),
537
- locale
538
- });
539
- }
540
- }
541
- return {
542
- success: true,
543
- translatedDocuments,
544
- sourceLocale: data.sourceLocale,
545
- requestId: data.requestId,
546
- // Keep deprecated field for backward compatibility
547
- translations: data.translations
548
- };
549
- }
550
- // Backward compatibility: single translatedContent object (convert to array)
551
- if (data.translatedContent) {
552
- const targetLocale = request.payload.metadata.targetLanguage ||
553
- request.payload.metadata.targetLocales?.[0];
554
- // Normalize fields to ensure consistency
555
- const normalizedContent = {
556
- ...data.translatedContent,
557
- fields: this.normalizeTranslatedFields(data.translatedContent.fields || {}),
558
- locale: targetLocale
559
- };
560
- return {
561
- success: true,
562
- translatedDocuments: [normalizedContent],
563
- sourceLocale: request.payload.metadata.sourceLanguage,
564
- requestId: data.requestId,
565
- // Keep deprecated field for backward compatibility
566
- translatedContent: data.translatedContent
567
- };
568
- }
569
- // Fallback: treat data.content as translatedContent
570
- if (data.content) {
571
- const targetLocale = request.payload.metadata.targetLanguage ||
572
- request.payload.metadata.targetLocales?.[0];
573
- // Normalize fields to ensure consistency
574
- const normalizedContent = {
575
- ...data.content,
576
- fields: this.normalizeTranslatedFields(data.content.fields || {}),
577
- locale: targetLocale
578
- };
579
- return {
580
- success: true,
581
- translatedDocuments: [normalizedContent],
582
- sourceLocale: request.payload.metadata.sourceLanguage,
583
- requestId: data.requestId,
584
- // Keep deprecated field for backward compatibility
585
- translatedContent: data.content
586
- };
587
- }
588
- throw new Error('Invalid response format: missing translatedDocuments, translations, or translatedContent');
589
- }
590
- catch (error) {
591
- console.error(`Translation request failed for document ${request.documentId}:`, error);
592
- return {
593
- success: false,
594
- error: error instanceof Error ? error.message : 'Unknown error occurred'
595
- };
596
- }
597
- }
598
- /**
599
- * Log translation request to console for verification
600
- * Requirements: 1.3, 2.4
601
- */
602
- logTranslationRequest(request) {
603
- console.log('Translation Request:', {
604
- timestamp: new Date().toISOString(),
605
- documentId: request.documentId,
606
- endpoint: request.endpoint,
607
- payload: request.payload
608
- });
609
- }
610
- /**
611
- * Process bulk translation for multiple documents
612
- * Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.7
613
- *
614
- * @param contents - Array of document contents to translate
615
- * @param documentType - Type of the documents
616
- * @param sourceLanguage - Source language code (optional)
617
- * @param targetLanguage - Single target language code (optional, for backward compatibility)
618
- * @param targetLocales - Array of target locale codes (optional, for multi-locale support)
619
- */
620
- async processBulkTranslation(contents, documentType = 'document', sourceLanguage, targetLanguage, targetLocales) {
621
- const summary = {
622
- totalDocuments: contents.length,
623
- processedDocuments: 0,
624
- failedDocuments: 0,
625
- requests: [],
626
- responses: []
627
- };
628
- const localeCount = targetLocales?.length || 1;
629
- console.log(`Starting bulk translation for ${contents.length} documents to ${localeCount} locale(s)`);
630
- for (const content of contents) {
631
- try {
632
- // Prepare translation request for each document
633
- const request = this.prepareTranslationRequest(content, documentType, sourceLanguage, targetLanguage, targetLocales);
634
- // Send the translation request
635
- const response = await this.sendTranslationRequest(request);
636
- // Add to summary
637
- summary.requests.push(request);
638
- summary.responses.push(response);
639
- if (response.success) {
640
- summary.processedDocuments++;
641
- }
642
- else {
643
- summary.failedDocuments++;
644
- }
645
- }
646
- catch (error) {
647
- console.error(`Failed to process document ${content.documentId}:`, error);
648
- summary.failedDocuments++;
649
- summary.responses.push({
650
- success: false,
651
- error: error instanceof Error ? error.message : 'Unknown error occurred'
652
- });
653
- }
654
- }
655
- // Log bulk operation summary
656
- this.logBulkTranslationSummary(summary);
657
- return summary;
658
- }
659
- /**
660
- * Log bulk translation summary
661
- * Requirements: 2.5
662
- */
663
- logBulkTranslationSummary(summary) {
664
- console.log('Bulk Translation Summary:', {
665
- timestamp: new Date().toISOString(),
666
- totalDocuments: summary.totalDocuments,
667
- processedDocuments: summary.processedDocuments,
668
- failedDocuments: summary.failedDocuments,
669
- successRate: summary.totalDocuments > 0
670
- ? ((summary.processedDocuments / summary.totalDocuments) * 100).toFixed(2) + '%'
671
- : '0%'
672
- });
673
- }
674
- /**
675
- * Update the placeholder endpoint
676
- */
677
- setEndpoint(endpoint) {
678
- this.placeholderEndpoint = endpoint;
679
- }
680
- /**
681
- * Get the current endpoint
682
- */
683
- getEndpoint() {
684
- return this.placeholderEndpoint;
685
- }
686
- }
687
- //# sourceMappingURL=translationService.js.map