sanity-plugin-transifex

5.1.115.1.12
~

Modified (4 files)

Index: package/dist/index.js
===================================================================
--- package/dist/index.js
+++ package/dist/index.js
@@ -123,9 +123,10 @@
 		});
 		if (!downloadResponse.ok) throw Error(`Failed to create translation download request in Transifex. Status: ${downloadResponse.status}`);
 		let translationDownloadId = (await downloadResponse.json())?.data?.id;
 		if (!translationDownloadId) throw Error("Failed to create translation download request in Transifex. Missing download id.");
-		return handleFileDownload(await pollForFileDownloadLocation(resourceDownloadUrl, translationDownloadId, getHeaders(secrets)));
+		let headers = getHeaders(secrets), location = await pollForFileDownloadLocation(resourceDownloadUrl, translationDownloadId, headers);
+		return handleFileDownload(location);
 	}
 }, defaultDocumentLevelConfig = {
 	...baseDocumentLevelConfig,
 	adapter: TransifexAdapter,
Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,7 +1,7 @@
 {
   "name": "sanity-plugin-transifex",
-  "version": "5.1.11",
+  "version": "5.1.12",
   "description": "This plugin provides an in-studio integration with Transifex. It allows your editors to send any document to Transifex with the click of a button, monitor ongoing translations, and import partial or complete translations back into the studio.",
   "keywords": [
     "sanity",
     "sanity-plugin"
@@ -26,21 +26,21 @@
     ".": "./dist/index.js",
     "./package.json": "./package.json"
   },
   "dependencies": {
-    "sanity-translations-tab": "^6.1.11"
+    "sanity-translations-tab": "^6.1.12"
   },
   "devDependencies": {
     "@sanity/tsconfig": "^2.2.0",
-    "@sanity/tsdown-config": "^0.11.0",
+    "@sanity/tsdown-config": "^0.13.1",
     "@types/react": "^19.2.17",
     "@types/react-dom": "^19.2.3",
     "babel-plugin-react-compiler": "^1.0.0",
     "react": "^19.2.7",
     "react-dom": "^19.2.7",
     "sanity": "^6.3.0",
     "styled-components": "^6.4.3",
-    "tsdown": "^0.22.3"
+    "tsdown": "^0.22.5"
   },
   "peerDependencies": {
     "react": "^19.2",
     "react-dom": "^19.2",
Index: package/dist/index.d.ts.map
===================================================================
--- package/dist/index.d.ts.map
+++ package/dist/index.d.ts.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"index.d.ts","names":[],"sources":["../src/transifexAdapter/index.ts","../src/index.ts"],"mappings":";cAOa,gBAAA,EAAkB,OAK9B;AAAA,UCYS,aAAA;EACR,OAAA,EAAS,OAAA;EACT,gBAAA;EACA,oBAAA,GACE,EAAA,UACA,OAAA,EAAS,0BAAA,KACN,OAAA,CAAQ,MAAA;EACb,iBAAA,GACE,EAAA,UACA,QAAA,UACA,GAAA,UACA,OAAA,EAAS,0BAAA,KACN,OAAA;AAAA;AAAA,cAED,0BAAA,EAA4B,aAIjC;AAAA,cAEK,yBAAA,EAA2B,aAIhC;AAAA,cAEK,uBAAA,EAAyB,aAI9B;AAAA,cAGK,sBAAA,EAAwB,aAI7B"}
\ No newline at end of file
+{"version":3,"file":"index.d.ts","names":[],"sources":["../src/transifexAdapter/index.ts","../src/index.ts"],"mappings":";cAOa,kBAAkB;UCiBrB;EACR,SAAS;EACT;EACA,uBACE,YACA,SAAS,+BACN,QAAQ;EACb,oBACE,YACA,kBACA,aACA,SAAS,+BACN;;cAED,4BAA4B;cAM5B,2BAA2B;cAM3B,yBAAyB;cAOzB,wBAAwB"}
\ No newline at end of file
Index: package/dist/index.js.map
===================================================================
--- package/dist/index.js.map
+++ package/dist/index.js.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"index.js","names":["Secrets","baseTransifexUrl","getHeaders","secrets","Record","token","projOrgSlug","organization","project","Adapter","Secrets","baseTransifexUrl","projOrgSlug","getHeaders","getLocales","secrets","locales","response","fetch","headers","ok","Error","status","json","then","res","data","map","lang","Record","enabled","description","localeId","Adapter","Secrets","getLocales","baseTransifexUrl","projOrgSlug","getHeaders","getTranslationTask","documentId","secrets","taskId","locales","projectFilter","resourceFilter","task","fetch","headers","then","res","ok","json","status","data","Error","map","locale","Record","reviewedStrings","Number","totalStrings","localeId","split","progress","isFinite","Math","floor","localeIds","l","validLocales","filter","find","id","Adapter","Secrets","getTranslationTask","baseTransifexUrl","projOrgSlug","getHeaders","createResource","doc","Record","documentId","secrets","resourceCreateBody","data","attributes","accept_translations","name","slug","relationships","i18n_format","id","type","project","response","fetch","headers","method","body","JSON","stringify","ok","Error","status","res","json","resourceId","createTask","document","_localeIds","resourceResponse","resource","resourceUploadUrl","resourceUploadBody","content","content_encoding","uploadResponse","Adapter","Secrets","baseTransifexUrl","getHeaders","pollForFileDownloadLocation","resourceDownloadUrl","translationDownloadId","headers","Record","retryCount","maxRetries","Promise","response","fetch","Error","status","console","info","resolve","setTimeout","redirected","url","error","handleFileDownload","then","res","text","getTranslation","taskId","localeId","secrets","resourceDownloadBody","data","attributes","content_encoding","relationships","language","id","type","resource","downloadResponse","method","body","JSON","stringify","ok","download","json","location","Adapter","createTask","getLocales","getTranslation","getTranslationTask","TransifexAdapter","baseDocumentLevelConfig","legacyDocumentLevelConfig","baseLegacyDocumentLevelConfig","baseFieldLevelConfig","baseI18nArrayConfig","Adapter","TranslationFunctionContext","TransifexAdapter","findLatestDraft","BaseDocumentDeserializer","BaseDocumentSerializer","BaseDocumentMerger","defaultStopTypes","customSerializers","legacyDocumentLevelPatch","documentLevelPatch","fieldLevelPatch","i18nArrayPatch","TranslationsTab","ConfigOptions","adapter","secretsNamespace","exportForTranslation","id","context","Promise","Record","importTranslation","localeId","doc","defaultDocumentLevelConfig","defaultFieldLevelConfig","defaultI18nArrayConfig"],"sources":["../src/transifexAdapter/helpers.ts","../src/transifexAdapter/getLocales.ts","../src/transifexAdapter/getTranslationTask.ts","../src/transifexAdapter/createTask.ts","../src/transifexAdapter/getTranslation.ts","../src/transifexAdapter/index.ts","../src/index.ts"],"sourcesContent":["import type {Secrets} from 'sanity-translations-tab'\n\nexport const baseTransifexUrl = 'https://rest.api.transifex.com'\n\nexport const getHeaders = (secrets: Secrets | null): Record<string, string> => ({\n  'Authorization': `Bearer ${secrets?.token}`,\n  'Content-Type': 'application/vnd.api+json',\n})\n\nexport const projOrgSlug = (secrets: Secrets | null): string =>\n  `o:${secrets?.organization}:p:${secrets?.project}`\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nexport const getLocales: Adapter['getLocales'] = async (secrets: Secrets | null) => {\n  let locales = []\n  if (secrets) {\n    const response = await fetch(`${baseTransifexUrl}/projects/${projOrgSlug(secrets)}/languages`, {\n      headers: getHeaders(secrets),\n    })\n\n    if (!response.ok) {\n      throw Error(`Failed to retrieve locales from Transifex. Status: ${response.status}`)\n    }\n\n    locales = await response.json().then((res) =>\n      res.data.map((lang: Record<string, any>) => ({\n        enabled: true,\n        description: lang['attributes']['name'],\n        localeId: lang['attributes']['code'],\n      })),\n    )\n  }\n  return locales\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {getLocales} from './getLocales'\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nexport const getTranslationTask: Adapter['getTranslationTask'] = async (\n  documentId: string,\n  secrets: Secrets | null,\n) => {\n  if (!documentId || !secrets) {\n    return {\n      taskId: documentId,\n      documentId: documentId,\n      locales: [],\n    }\n  }\n  const projectFilter = `filter[project]=${projOrgSlug(secrets)}`\n  const resourceFilter = `filter[resource]=${projOrgSlug(secrets)}:r:${documentId}`\n  const task = await fetch(\n    `${baseTransifexUrl}/resource_language_stats?${projectFilter}&${resourceFilter}`,\n    {headers: getHeaders(secrets)},\n  )\n    .then((res) => {\n      if (res.ok) {\n        return res.json()\n      }\n      //normal -- just means that this task doesn't exist yet.\n      else if (res.status === 404) {\n        return {data: []}\n      }\n      throw Error(`Failed to retrieve tasks from Transifex. Status: ${res.status}`)\n    })\n    .then((res) => ({\n      taskId: `${projOrgSlug(secrets)}:r:${documentId}`,\n      documentId: documentId,\n      locales: res.data.map((locale: Record<string, any>) => {\n        const reviewedStrings = Number(locale['attributes']['reviewed_strings'])\n        const totalStrings = Number(locale['attributes']['total_strings'])\n\n        return {\n          localeId: locale['relationships']['language']['data']['id'].split(':')[1],\n          progress:\n            Number.isFinite(reviewedStrings) && Number.isFinite(totalStrings) && totalStrings > 0\n              ? Math.floor((100 * reviewedStrings) / totalStrings)\n              : 0,\n        }\n      }),\n    }))\n\n  const locales = await getLocales(secrets)\n  const localeIds = locales.map((l: Record<string, any>) => l['localeId'])\n  const validLocales = task.locales.filter((locale: Record<string, any>) =>\n    localeIds.find((id: string) => id === locale['localeId']),\n  )\n  task.locales = validLocales\n\n  return task\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {getTranslationTask} from './getTranslationTask'\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nconst createResource = async (\n  doc: Record<string, any>,\n  documentId: string,\n  secrets: Secrets | null,\n) => {\n  const resourceCreateBody = {\n    data: {\n      attributes: {\n        accept_translations: true,\n        name: doc['name'],\n        slug: documentId,\n      },\n      relationships: {\n        i18n_format: {\n          data: {\n            id: 'HTML_FRAGMENT',\n            type: 'i18n_formats',\n          },\n        },\n        project: {\n          data: {\n            id: projOrgSlug(secrets),\n            type: 'projects',\n          },\n        },\n      },\n      type: 'resources',\n    },\n  }\n\n  const response = await fetch(`${baseTransifexUrl}/resources`, {\n    headers: getHeaders(secrets),\n    method: 'POST',\n    body: JSON.stringify(resourceCreateBody),\n  })\n\n  if (!response.ok) {\n    throw Error(`Failed to create Transifex resource. Status: ${response.status}`)\n  }\n\n  const res = await response.json()\n  const resourceId = res?.data?.id\n\n  if (!resourceId) {\n    throw Error('Failed to create Transifex resource. Missing resource id in response.')\n  }\n\n  return resourceId\n}\n\nexport const createTask: Adapter['createTask'] = async (\n  documentId: string,\n  document: Record<string, any>,\n  _localeIds: string[],\n  secrets: Secrets | null,\n) => {\n  if (!documentId || !secrets) {\n    throw Error('Missing documentId or Transifex secrets.')\n  }\n\n  const resourceResponse = await fetch(\n    `${baseTransifexUrl}/resources/${projOrgSlug(secrets)}:r:${documentId}`,\n    {headers: getHeaders(secrets)},\n  )\n  let resourceId: string | null = null\n\n  if (resourceResponse.status === 404) {\n    resourceId = null\n  } else if (!resourceResponse.ok) {\n    throw Error(`Failed to retrieve Transifex resource. Status: ${resourceResponse.status}`)\n  } else {\n    const resource = await resourceResponse.json()\n    resourceId = resource.data ? resource.data.id : null\n  }\n\n  if (!resourceId) {\n    resourceId = await createResource(document, documentId, secrets)\n  }\n\n  const resourceUploadUrl = `${baseTransifexUrl}/resource_strings_async_uploads`\n  const resourceUploadBody = {\n    data: {\n      attributes: {\n        content: document['content'],\n        content_encoding: 'text',\n      },\n      relationships: {\n        resource: {\n          data: {\n            id: resourceId,\n            type: 'resources',\n          },\n        },\n      },\n      type: 'resource_strings_async_uploads',\n    },\n  }\n\n  const uploadResponse = await fetch(resourceUploadUrl, {\n    method: 'POST',\n    body: JSON.stringify(resourceUploadBody),\n    headers: getHeaders(secrets),\n  })\n\n  if (!uploadResponse.ok) {\n    throw Error(`Failed to upload resource strings to Transifex. Status: ${uploadResponse.status}`)\n  }\n\n  return getTranslationTask(documentId, secrets)\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {baseTransifexUrl, getHeaders} from './helpers'\n\nconst pollForFileDownloadLocation = async (\n  resourceDownloadUrl: string,\n  translationDownloadId: string,\n  headers: Record<string, any>,\n  retryCount = 0,\n  maxRetries = 20,\n): Promise<string> => {\n  const response = await fetch(`${resourceDownloadUrl}/${translationDownloadId}`, {\n    headers: headers,\n  })\n\n  if (retryCount >= maxRetries) {\n    throw Error(\n      `Failed to retrieve download location for translation download ID ${translationDownloadId} after ${maxRetries} retries.`,\n    )\n  }\n\n  if (response.status === 500) {\n    //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n    console.info(\n      `Transifex plugin message: Received 500 for translation download ID ${translationDownloadId}. Trying to reconnect...`,\n    )\n    await new Promise((resolve) => setTimeout(resolve, 3000))\n    return pollForFileDownloadLocation(\n      resourceDownloadUrl,\n      translationDownloadId,\n      headers,\n      retryCount + 1,\n      maxRetries,\n    )\n  } else if (response.redirected) {\n    //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n    console.info(\n      `Transifex plugin message: Received redirect for translation download ID ${translationDownloadId}. Following redirect now for file download.`,\n    )\n    return response.url\n  } else if (response.status === 200) {\n    //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n    console.info(\n      `Transifex plugin message: Requested download location for translation download ID ${translationDownloadId}. Location is still pending, trying again.`,\n    )\n    await new Promise((resolve) => setTimeout(resolve, 3000))\n    return pollForFileDownloadLocation(\n      resourceDownloadUrl,\n      translationDownloadId,\n      headers,\n      retryCount + 1,\n      maxRetries,\n    )\n  } else if (response.status === 401 || response.status === 403) {\n    throw Error(\n      `Failed to retrieve download location for translation download ID ${translationDownloadId}. Status: ${response.status}`,\n    )\n  }\n  console.error(\n    `Transifex plugin message: Requested download location for translation download ID ${translationDownloadId} but received error code ${response.status}. Waiting and trying again.`,\n  )\n  await new Promise((resolve) => setTimeout(resolve, 3000))\n  return pollForFileDownloadLocation(\n    resourceDownloadUrl,\n    translationDownloadId,\n    headers,\n    retryCount + 1,\n    maxRetries,\n  )\n}\n\nconst handleFileDownload = (url: string) => {\n  return fetch(url).then((res) => res.text())\n}\n\nexport const getTranslation: Adapter['getTranslation'] = async (\n  taskId: string,\n  localeId: string,\n  secrets: Secrets | null,\n) => {\n  if (!secrets) {\n    throw Error('Missing Transifex secrets.')\n  }\n\n  const resourceDownloadBody = {\n    data: {\n      attributes: {\n        content_encoding: 'text',\n      },\n      relationships: {\n        language: {\n          data: {\n            id: `l:${localeId}`,\n            type: 'languages',\n          },\n        },\n        resource: {\n          data: {\n            id: taskId,\n            type: 'resources',\n          },\n        },\n      },\n      type: 'resource_translations_async_downloads',\n    },\n  }\n\n  const resourceDownloadUrl = `${baseTransifexUrl}/resource_translations_async_downloads`\n  const downloadResponse = await fetch(resourceDownloadUrl, {\n    headers: getHeaders(secrets),\n    method: 'POST',\n    body: JSON.stringify(resourceDownloadBody),\n  })\n\n  if (!downloadResponse.ok) {\n    throw Error(\n      `Failed to create translation download request in Transifex. Status: ${downloadResponse.status}`,\n    )\n  }\n\n  const download = await downloadResponse.json()\n  const translationDownloadId = download?.data?.id\n\n  if (!translationDownloadId) {\n    throw Error('Failed to create translation download request in Transifex. Missing download id.')\n  }\n\n  const headers = getHeaders(secrets)\n  const location = await pollForFileDownloadLocation(\n    resourceDownloadUrl,\n    translationDownloadId,\n    headers,\n  )\n  return handleFileDownload(location)\n}\n","import type {Adapter} from 'sanity-translations-tab'\n\nimport {createTask} from './createTask'\nimport {getLocales} from './getLocales'\nimport {getTranslation} from './getTranslation'\nimport {getTranslationTask} from './getTranslationTask'\n\nexport const TransifexAdapter: Adapter = {\n  getLocales,\n  getTranslationTask,\n  createTask,\n  getTranslation,\n}\n","import {\n  baseDocumentLevelConfig,\n  legacyDocumentLevelConfig as baseLegacyDocumentLevelConfig,\n  baseFieldLevelConfig,\n  baseI18nArrayConfig,\n} from 'sanity-translations-tab'\nimport type {Adapter, TranslationFunctionContext} from 'sanity-translations-tab'\n\nimport {TransifexAdapter} from './transifexAdapter'\n\nexport {\n  findLatestDraft,\n  BaseDocumentDeserializer,\n  BaseDocumentSerializer,\n  BaseDocumentMerger,\n  defaultStopTypes,\n  customSerializers,\n  legacyDocumentLevelPatch,\n  documentLevelPatch,\n  fieldLevelPatch,\n  i18nArrayPatch,\n  TranslationsTab,\n} from 'sanity-translations-tab'\n\ninterface ConfigOptions {\n  adapter: Adapter\n  secretsNamespace: string | null\n  exportForTranslation: (\n    id: string,\n    context: TranslationFunctionContext,\n  ) => Promise<Record<string, any>>\n  importTranslation: (\n    id: string,\n    localeId: string,\n    doc: string,\n    context: TranslationFunctionContext,\n  ) => Promise<void>\n}\nconst defaultDocumentLevelConfig: ConfigOptions = {\n  ...baseDocumentLevelConfig,\n  adapter: TransifexAdapter,\n  secretsNamespace: 'transifex',\n}\n\nconst legacyDocumentLevelConfig: ConfigOptions = {\n  ...baseLegacyDocumentLevelConfig,\n  adapter: TransifexAdapter,\n  secretsNamespace: 'transifex',\n}\n\nconst defaultFieldLevelConfig: ConfigOptions = {\n  ...baseFieldLevelConfig,\n  adapter: TransifexAdapter,\n  secretsNamespace: 'transifex',\n}\n\n//for documents using sanity-plugin-internationalized-array fields\nconst defaultI18nArrayConfig: ConfigOptions = {\n  ...baseI18nArrayConfig,\n  adapter: TransifexAdapter,\n  secretsNamespace: 'transifex',\n}\n\nexport {\n  TransifexAdapter,\n  defaultDocumentLevelConfig,\n  defaultFieldLevelConfig,\n  defaultI18nArrayConfig,\n  legacyDocumentLevelConfig,\n}\n"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"index.js","names":["Secrets","baseTransifexUrl","getHeaders","secrets","Record","token","projOrgSlug","organization","project","Adapter","Secrets","baseTransifexUrl","projOrgSlug","getHeaders","getLocales","secrets","locales","response","fetch","headers","ok","Error","status","json","then","res","data","map","lang","Record","enabled","description","localeId","Adapter","Secrets","getLocales","baseTransifexUrl","projOrgSlug","getHeaders","getTranslationTask","documentId","secrets","taskId","locales","projectFilter","resourceFilter","task","fetch","headers","then","res","ok","json","status","data","Error","map","locale","Record","reviewedStrings","Number","totalStrings","localeId","split","progress","isFinite","Math","floor","localeIds","l","validLocales","filter","find","id","Adapter","Secrets","getTranslationTask","baseTransifexUrl","projOrgSlug","getHeaders","createResource","doc","Record","documentId","secrets","resourceCreateBody","data","attributes","accept_translations","name","slug","relationships","i18n_format","id","type","project","response","fetch","headers","method","body","JSON","stringify","ok","Error","status","res","json","resourceId","createTask","document","_localeIds","resourceResponse","resource","resourceUploadUrl","resourceUploadBody","content","content_encoding","uploadResponse","Adapter","Secrets","baseTransifexUrl","getHeaders","pollForFileDownloadLocation","resourceDownloadUrl","translationDownloadId","headers","Record","retryCount","maxRetries","Promise","response","fetch","Error","status","console","info","resolve","setTimeout","redirected","url","error","handleFileDownload","then","res","text","getTranslation","taskId","localeId","secrets","resourceDownloadBody","data","attributes","content_encoding","relationships","language","id","type","resource","downloadResponse","method","body","JSON","stringify","ok","download","json","location","Adapter","createTask","getLocales","getTranslation","getTranslationTask","TransifexAdapter","baseDocumentLevelConfig","legacyDocumentLevelConfig","baseLegacyDocumentLevelConfig","baseFieldLevelConfig","baseI18nArrayConfig","Adapter","TranslationFunctionContext","TransifexAdapter","findLatestDraft","BaseDocumentDeserializer","BaseDocumentSerializer","BaseDocumentMerger","defaultStopTypes","customSerializers","legacyDocumentLevelPatch","documentLevelPatch","fieldLevelPatch","i18nArrayPatch","TranslationsTab","ConfigOptions","adapter","secretsNamespace","exportForTranslation","id","context","Promise","Record","importTranslation","localeId","doc","defaultDocumentLevelConfig","defaultFieldLevelConfig","defaultI18nArrayConfig"],"sources":["../src/transifexAdapter/helpers.ts","../src/transifexAdapter/getLocales.ts","../src/transifexAdapter/getTranslationTask.ts","../src/transifexAdapter/createTask.ts","../src/transifexAdapter/getTranslation.ts","../src/transifexAdapter/index.ts","../src/index.ts"],"sourcesContent":["import type {Secrets} from 'sanity-translations-tab'\n\nexport const baseTransifexUrl = 'https://rest.api.transifex.com'\n\nexport const getHeaders = (secrets: Secrets | null): Record<string, string> => ({\n  'Authorization': `Bearer ${secrets?.token}`,\n  'Content-Type': 'application/vnd.api+json',\n})\n\nexport const projOrgSlug = (secrets: Secrets | null): string =>\n  `o:${secrets?.organization}:p:${secrets?.project}`\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nexport const getLocales: Adapter['getLocales'] = async (secrets: Secrets | null) => {\n  let locales = []\n  if (secrets) {\n    const response = await fetch(`${baseTransifexUrl}/projects/${projOrgSlug(secrets)}/languages`, {\n      headers: getHeaders(secrets),\n    })\n\n    if (!response.ok) {\n      throw Error(`Failed to retrieve locales from Transifex. Status: ${response.status}`)\n    }\n\n    locales = await response.json().then((res) =>\n      res.data.map((lang: Record<string, any>) => ({\n        enabled: true,\n        description: lang['attributes']['name'],\n        localeId: lang['attributes']['code'],\n      })),\n    )\n  }\n  return locales\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {getLocales} from './getLocales'\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nexport const getTranslationTask: Adapter['getTranslationTask'] = async (\n  documentId: string,\n  secrets: Secrets | null,\n) => {\n  if (!documentId || !secrets) {\n    return {\n      taskId: documentId,\n      documentId: documentId,\n      locales: [],\n    }\n  }\n  const projectFilter = `filter[project]=${projOrgSlug(secrets)}`\n  const resourceFilter = `filter[resource]=${projOrgSlug(secrets)}:r:${documentId}`\n  const task = await fetch(\n    `${baseTransifexUrl}/resource_language_stats?${projectFilter}&${resourceFilter}`,\n    {headers: getHeaders(secrets)},\n  )\n    .then((res) => {\n      if (res.ok) {\n        return res.json()\n      }\n      //normal -- just means that this task doesn't exist yet.\n      else if (res.status === 404) {\n        return {data: []}\n      }\n      throw Error(`Failed to retrieve tasks from Transifex. Status: ${res.status}`)\n    })\n    .then((res) => ({\n      taskId: `${projOrgSlug(secrets)}:r:${documentId}`,\n      documentId: documentId,\n      locales: res.data.map((locale: Record<string, any>) => {\n        const reviewedStrings = Number(locale['attributes']['reviewed_strings'])\n        const totalStrings = Number(locale['attributes']['total_strings'])\n\n        return {\n          localeId: locale['relationships']['language']['data']['id'].split(':')[1],\n          progress:\n            Number.isFinite(reviewedStrings) && Number.isFinite(totalStrings) && totalStrings > 0\n              ? Math.floor((100 * reviewedStrings) / totalStrings)\n              : 0,\n        }\n      }),\n    }))\n\n  const locales = await getLocales(secrets)\n  const localeIds = locales.map((l: Record<string, any>) => l['localeId'])\n  const validLocales = task.locales.filter((locale: Record<string, any>) =>\n    localeIds.find((id: string) => id === locale['localeId']),\n  )\n  task.locales = validLocales\n\n  return task\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {getTranslationTask} from './getTranslationTask'\nimport {baseTransifexUrl, projOrgSlug, getHeaders} from './helpers'\n\nconst createResource = async (\n  doc: Record<string, any>,\n  documentId: string,\n  secrets: Secrets | null,\n) => {\n  const resourceCreateBody = {\n    data: {\n      attributes: {\n        accept_translations: true,\n        name: doc['name'],\n        slug: documentId,\n      },\n      relationships: {\n        i18n_format: {\n          data: {\n            id: 'HTML_FRAGMENT',\n            type: 'i18n_formats',\n          },\n        },\n        project: {\n          data: {\n            id: projOrgSlug(secrets),\n            type: 'projects',\n          },\n        },\n      },\n      type: 'resources',\n    },\n  }\n\n  const response = await fetch(`${baseTransifexUrl}/resources`, {\n    headers: getHeaders(secrets),\n    method: 'POST',\n    body: JSON.stringify(resourceCreateBody),\n  })\n\n  if (!response.ok) {\n    throw Error(`Failed to create Transifex resource. Status: ${response.status}`)\n  }\n\n  const res = await response.json()\n  const resourceId = res?.data?.id\n\n  if (!resourceId) {\n    throw Error('Failed to create Transifex resource. Missing resource id in response.')\n  }\n\n  return resourceId\n}\n\nexport const createTask: Adapter['createTask'] = async (\n  documentId: string,\n  document: Record<string, any>,\n  _localeIds: string[],\n  secrets: Secrets | null,\n) => {\n  if (!documentId || !secrets) {\n    throw Error('Missing documentId or Transifex secrets.')\n  }\n\n  const resourceResponse = await fetch(\n    `${baseTransifexUrl}/resources/${projOrgSlug(secrets)}:r:${documentId}`,\n    {headers: getHeaders(secrets)},\n  )\n  let resourceId: string | null = null\n\n  if (resourceResponse.status === 404) {\n    resourceId = null\n  } else if (!resourceResponse.ok) {\n    throw Error(`Failed to retrieve Transifex resource. Status: ${resourceResponse.status}`)\n  } else {\n    const resource = await resourceResponse.json()\n    resourceId = resource.data ? resource.data.id : null\n  }\n\n  if (!resourceId) {\n    resourceId = await createResource(document, documentId, secrets)\n  }\n\n  const resourceUploadUrl = `${baseTransifexUrl}/resource_strings_async_uploads`\n  const resourceUploadBody = {\n    data: {\n      attributes: {\n        content: document['content'],\n        content_encoding: 'text',\n      },\n      relationships: {\n        resource: {\n          data: {\n            id: resourceId,\n            type: 'resources',\n          },\n        },\n      },\n      type: 'resource_strings_async_uploads',\n    },\n  }\n\n  const uploadResponse = await fetch(resourceUploadUrl, {\n    method: 'POST',\n    body: JSON.stringify(resourceUploadBody),\n    headers: getHeaders(secrets),\n  })\n\n  if (!uploadResponse.ok) {\n    throw Error(`Failed to upload resource strings to Transifex. Status: ${uploadResponse.status}`)\n  }\n\n  return getTranslationTask(documentId, secrets)\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {baseTransifexUrl, getHeaders} from './helpers'\n\nconst pollForFileDownloadLocation = async (\n  resourceDownloadUrl: string,\n  translationDownloadId: string,\n  headers: Record<string, any>,\n  retryCount = 0,\n  maxRetries = 20,\n): Promise<string> => {\n  const response = await fetch(`${resourceDownloadUrl}/${translationDownloadId}`, {\n    headers: headers,\n  })\n\n  if (retryCount >= maxRetries) {\n    throw Error(\n      `Failed to retrieve download location for translation download ID ${translationDownloadId} after ${maxRetries} retries.`,\n    )\n  }\n\n  if (response.status === 500) {\n    //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n    console.info(\n      `Transifex plugin message: Received 500 for translation download ID ${translationDownloadId}. Trying to reconnect...`,\n    )\n    await new Promise((resolve) => setTimeout(resolve, 3000))\n    return pollForFileDownloadLocation(\n      resourceDownloadUrl,\n      translationDownloadId,\n      headers,\n      retryCount + 1,\n      maxRetries,\n    )\n  } else if (response.redirected) {\n    //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n    console.info(\n      `Transifex plugin message: Received redirect for translation download ID ${translationDownloadId}. Following redirect now for file download.`,\n    )\n    return response.url\n  } else if (response.status === 200) {\n    //eslint-disable-next-line no-console -- this is for developer feedback/debugging\n    console.info(\n      `Transifex plugin message: Requested download location for translation download ID ${translationDownloadId}. Location is still pending, trying again.`,\n    )\n    await new Promise((resolve) => setTimeout(resolve, 3000))\n    return pollForFileDownloadLocation(\n      resourceDownloadUrl,\n      translationDownloadId,\n      headers,\n      retryCount + 1,\n      maxRetries,\n    )\n  } else if (response.status === 401 || response.status === 403) {\n    throw Error(\n      `Failed to retrieve download location for translation download ID ${translationDownloadId}. Status: ${response.status}`,\n    )\n  }\n  console.error(\n    `Transifex plugin message: Requested download location for translation download ID ${translationDownloadId} but received error code ${response.status}. Waiting and trying again.`,\n  )\n  await new Promise((resolve) => setTimeout(resolve, 3000))\n  return pollForFileDownloadLocation(\n    resourceDownloadUrl,\n    translationDownloadId,\n    headers,\n    retryCount + 1,\n    maxRetries,\n  )\n}\n\nconst handleFileDownload = (url: string) => {\n  return fetch(url).then((res) => res.text())\n}\n\nexport const getTranslation: Adapter['getTranslation'] = async (\n  taskId: string,\n  localeId: string,\n  secrets: Secrets | null,\n) => {\n  if (!secrets) {\n    throw Error('Missing Transifex secrets.')\n  }\n\n  const resourceDownloadBody = {\n    data: {\n      attributes: {\n        content_encoding: 'text',\n      },\n      relationships: {\n        language: {\n          data: {\n            id: `l:${localeId}`,\n            type: 'languages',\n          },\n        },\n        resource: {\n          data: {\n            id: taskId,\n            type: 'resources',\n          },\n        },\n      },\n      type: 'resource_translations_async_downloads',\n    },\n  }\n\n  const resourceDownloadUrl = `${baseTransifexUrl}/resource_translations_async_downloads`\n  const downloadResponse = await fetch(resourceDownloadUrl, {\n    headers: getHeaders(secrets),\n    method: 'POST',\n    body: JSON.stringify(resourceDownloadBody),\n  })\n\n  if (!downloadResponse.ok) {\n    throw Error(\n      `Failed to create translation download request in Transifex. Status: ${downloadResponse.status}`,\n    )\n  }\n\n  const download = await downloadResponse.json()\n  const translationDownloadId = download?.data?.id\n\n  if (!translationDownloadId) {\n    throw Error('Failed to create translation download request in Transifex. Missing download id.')\n  }\n\n  const headers = getHeaders(secrets)\n  const location = await pollForFileDownloadLocation(\n    resourceDownloadUrl,\n    translationDownloadId,\n    headers,\n  )\n  return handleFileDownload(location)\n}\n","import type {Adapter} from 'sanity-translations-tab'\n\nimport {createTask} from './createTask'\nimport {getLocales} from './getLocales'\nimport {getTranslation} from './getTranslation'\nimport {getTranslationTask} from './getTranslationTask'\n\nexport const TransifexAdapter: Adapter = {\n  getLocales,\n  getTranslationTask,\n  createTask,\n  getTranslation,\n}\n","import {\n  baseDocumentLevelConfig,\n  legacyDocumentLevelConfig as baseLegacyDocumentLevelConfig,\n  baseFieldLevelConfig,\n  baseI18nArrayConfig,\n} from 'sanity-translations-tab'\nimport type {Adapter, TranslationFunctionContext} from 'sanity-translations-tab'\n\nimport {TransifexAdapter} from './transifexAdapter'\n\nexport {\n  findLatestDraft,\n  BaseDocumentDeserializer,\n  BaseDocumentSerializer,\n  BaseDocumentMerger,\n  defaultStopTypes,\n  customSerializers,\n  legacyDocumentLevelPatch,\n  documentLevelPatch,\n  fieldLevelPatch,\n  i18nArrayPatch,\n  TranslationsTab,\n} from 'sanity-translations-tab'\n\ninterface ConfigOptions {\n  adapter: Adapter\n  secretsNamespace: string | null\n  exportForTranslation: (\n    id: string,\n    context: TranslationFunctionContext,\n  ) => Promise<Record<string, any>>\n  importTranslation: (\n    id: string,\n    localeId: string,\n    doc: string,\n    context: TranslationFunctionContext,\n  ) => Promise<void>\n}\nconst defaultDocumentLevelConfig: ConfigOptions = {\n  ...baseDocumentLevelConfig,\n  adapter: TransifexAdapter,\n  secretsNamespace: 'transifex',\n}\n\nconst legacyDocumentLevelConfig: ConfigOptions = {\n  ...baseLegacyDocumentLevelConfig,\n  adapter: TransifexAdapter,\n  secretsNamespace: 'transifex',\n}\n\nconst defaultFieldLevelConfig: ConfigOptions = {\n  ...baseFieldLevelConfig,\n  adapter: TransifexAdapter,\n  secretsNamespace: 'transifex',\n}\n\n//for documents using sanity-plugin-internationalized-array fields\nconst defaultI18nArrayConfig: ConfigOptions = {\n  ...baseI18nArrayConfig,\n  adapter: TransifexAdapter,\n  secretsNamespace: 'transifex',\n}\n\nexport {\n  TransifexAdapter,\n  defaultDocumentLevelConfig,\n  defaultFieldLevelConfig,\n  defaultI18nArrayConfig,\n  legacyDocumentLevelConfig,\n}\n"],"mappings":"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"}
\ No newline at end of file