sanity-plugin-studio-smartling

5.0.185.0.19
dist/index.js.map
~dist/index.js.mapModified
+1−1
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":[],"sources":["../src/adapter/helpers.ts","../src/adapter/getTranslationTask.ts","../src/adapter/createTask.ts","../src/adapter/getLocales.ts","../src/adapter/getTranslation.ts","../src/adapter/index.ts","../src/index.ts"],"sourcesContent":["import type {Secrets} from 'sanity-translations-tab'\n\nexport const authenticate = (secrets: Secrets): Promise<string> => {\n  const url = 'https://api.smartling.com/auth-api/v2/authenticate'\n  const headers = {\n    'content-type': 'application/json',\n    'X-URL': url,\n  }\n  const {secret, proxy} = secrets\n  if (!secret || !proxy) {\n    throw new Error(\n      'The Smartling adapter requires a secret key and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n  // `secret` is already a JSON string (e.g. `{\"userIdentifier\":\"…\",\"userSecret\":\"…\"}`),\n  // so it is sent as-is. Wrapping it in `JSON.stringify` would double-encode it into a\n  // quoted string and break authentication with proxies that forward the body verbatim.\n  return fetch(proxy, {\n    headers,\n    method: 'POST',\n    body: secret,\n  })\n    .then((res) => res.json())\n    .then((res) => {\n      const accessToken = res?.response?.data?.accessToken\n      if (!accessToken) {\n        const errMsg =\n          res?.response?.errors?.[0]?.message ||\n          'Could not authenticate with Smartling. Please check your secret key and proxy URL, per the plugin documentation.'\n        throw new Error(errMsg)\n      }\n      return accessToken\n    })\n}\n\nexport const getHeaders = (url: string, accessToken: string): Record<string, string> => ({\n  'Authorization': `Bearer ${accessToken}`,\n  'X-URL': url,\n})\n\nexport const findExistingJob = async (\n  documentId: string,\n  secrets: Secrets,\n  accessToken: string,\n): Promise<string> => {\n  const {project, proxy} = secrets\n  if (!project || !proxy) {\n    throw new Error(\n      'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n  const url = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs?jobName=${documentId}`\n  //first, try fetching from name resolution\n  let items = await fetch(proxy, {\n    headers: getHeaders(url, accessToken),\n  })\n    .then((res) => res.json())\n    .then((res) => res?.response?.data?.items)\n\n  if (!items || !items.length) {\n    //if that fails, try fetching by fileUri and check the referenceNumber\n    const refUrl = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs/search`\n    items = await fetch(proxy, {\n      headers: {\n        ...getHeaders(refUrl, accessToken),\n        'content-type': 'application/json',\n      },\n      method: 'POST',\n      body: JSON.stringify({\n        fileUris: [documentId],\n      }),\n    })\n      .then((res) => res.json())\n      .then((res) => res?.response?.data?.items)\n  }\n\n  if (items?.length) {\n    //smartling will fuzzy match job names. We need to be precise.\n    const correctJob = items\n      .filter((item: {jobStatus: string}) => item.jobStatus !== 'DELETED')\n      .find(\n        (item: {jobName: string; referenceNumber: string}) =>\n          (item.jobName && item.jobName === documentId) ||\n          (item.referenceNumber && item.referenceNumber === documentId),\n      )\n\n    if (correctJob) {\n      return correctJob.translationJobUid\n    }\n  }\n  return ''\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {authenticate, getHeaders, findExistingJob} from './helpers'\n\ninterface WorkflowProgressItem {\n  workflowStepSummaryReportItemList: {\n    wordCount: number\n  }[]\n}\n\ninterface SmartlingProgressItem {\n  targetLocaleId: string\n  progress: {\n    percentComplete: number\n    totalWordCount: number\n  }\n  workflowProgressReportList: WorkflowProgressItem[]\n}\n\nexport const getTranslationTask: Adapter['getTranslationTask'] = async (\n  documentId: string,\n  secrets: Secrets | null,\n) => {\n  if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {\n    return {\n      documentId,\n      taskId: documentId,\n      locales: [],\n    }\n  }\n\n  const {project, proxy} = secrets\n\n  const accessToken = await authenticate(secrets)\n  const taskId = await findExistingJob(documentId, secrets, accessToken)\n  if (!taskId) {\n    return {\n      documentId,\n      taskId: documentId,\n      locales: [],\n    }\n  }\n\n  const progressUrl = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs/${taskId}/progress`\n  const smartlingTask = await fetch(proxy, {\n    method: 'GET',\n    headers: getHeaders(progressUrl, accessToken),\n  })\n    .then((res) => res.json())\n    .then((res) => res.response.data)\n\n  let locales = []\n  if (smartlingTask && smartlingTask.contentProgressReport) {\n    locales = smartlingTask.contentProgressReport.map((item: SmartlingProgressItem) => {\n      let progress = item.progress ? item.progress.percentComplete : 0\n      //default to the first workflow -- it's likely what is being used\n      const progressItem = item.workflowProgressReportList?.[0]\n      if (progressItem && item.progress) {\n        //this is a list of the various steps in the workflow\n        if (\n          progressItem.workflowStepSummaryReportItemList &&\n          progressItem.workflowStepSummaryReportItemList.length > 1\n        ) {\n          //get the last step in the workflow -- usually \"published\"\n          const lastStep = progressItem.workflowStepSummaryReportItemList.at(-1)\n          //get the percentage of how many words have reached the last step\n          //guard against a 0 totalWordCount (e.g. empty documents) which would\n          //otherwise produce NaN/Infinity and surface as an invalid percentage\n          if (lastStep && lastStep.wordCount >= 0 && item.progress.totalWordCount > 0) {\n            progress = Math.floor((lastStep.wordCount / item.progress.totalWordCount) * 100)\n          }\n        }\n      }\n      return {\n        localeId: item.targetLocaleId,\n        progress,\n      }\n    })\n  }\n\n  return {\n    documentId,\n    locales,\n    //since our download is tied to document id for smartling, keep track of it as a task\n    taskId: documentId,\n    linkToVendorTask: `https://dashboard.smartling.com/app/projects/${project}/account-jobs/${project}:${taskId}`,\n  }\n}\n","import type {Adapter, Secrets, SerializedDocument} from 'sanity-translations-tab'\n\nimport {getTranslationTask} from './getTranslationTask'\nimport {authenticate, getHeaders, findExistingJob} from './helpers'\n\nconst createJob = (\n  jobName: string,\n  secrets: Secrets,\n  localeIds: string[],\n  accessToken: string,\n  documentId: string,\n) => {\n  const {project, proxy} = secrets\n  if (!project || !proxy) {\n    throw new Error(\n      'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n\n  const url = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs`\n  return fetch(proxy, {\n    method: 'POST',\n    headers: {\n      ...getHeaders(url, accessToken),\n      'content-type': 'application/json',\n    },\n    body: JSON.stringify({\n      jobName,\n      targetLocaleIds: localeIds,\n      referenceNumber: documentId,\n    }),\n  })\n    .then((res) => res.json())\n    .then((res) => res.response.data.translationJobUid)\n}\n\n/* we're using batches here because it eliminates some\n * new string authorization issues for updating existing jobs,\n * and is able to be used for new bulk\n * job functionality.\n */\n\nconst createJobBatch = (\n  jobId: string,\n  secrets: Secrets,\n  documentId: string,\n  accessToken: string,\n  localeIds: string[],\n  workflowUid?: string,\n) => {\n  const {project, proxy} = secrets\n  if (!project || !proxy) {\n    throw new Error(\n      'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n  const url = `https://api.smartling.com/job-batches-api/v2/projects/${project}/batches`\n  const reqBody: {\n    authorize: boolean\n    translationJobUid: string\n    fileUris: string[]\n    localeWorkflows?: {targetLocaleId: string; workflowUid: string}[]\n  } = {\n    authorize: true,\n    translationJobUid: jobId,\n    fileUris: [documentId],\n  }\n\n  if (workflowUid) {\n    reqBody.localeWorkflows = localeIds.map((l) => ({\n      targetLocaleId: l,\n      workflowUid,\n    }))\n  }\n\n  return fetch(proxy, {\n    method: 'POST',\n    headers: {\n      ...getHeaders(url, accessToken),\n      'content-type': 'application/json',\n    },\n    body: JSON.stringify(reqBody),\n  })\n    .then((res) => res.json())\n    .then((res) => res.response.data.batchUid)\n}\n\nconst uploadFileToBatch = (\n  batchUid: string,\n  documentId: string,\n  document: SerializedDocument,\n  secrets: Secrets,\n  localeIds: string[],\n  accessToken: string,\n  callbackUrl?: string,\n) => {\n  const {project, proxy} = secrets\n  if (!project || !proxy) {\n    throw new Error(\n      'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n  const url = `https://api.smartling.com/job-batches-api/v2/projects/${project}/batches/${batchUid}/file`\n  const formData = new FormData()\n  formData.append('fileUri', documentId)\n  formData.append('fileType', 'html')\n  formData.append('file', new Blob([document.content]), `${document.name}.html`)\n  localeIds.forEach((localeId) => formData.append('localeIdsToAuthorize[]', localeId))\n  if (callbackUrl) {\n    formData.append('callbackUrl', callbackUrl)\n  }\n\n  return fetch(proxy, {\n    method: 'POST',\n    headers: getHeaders(url, accessToken),\n    body: formData,\n  }).then((res) => res.json())\n}\n\nexport const createTask: Adapter['createTask'] = async (\n  documentId: string,\n  document: SerializedDocument,\n  localeIds: string[],\n  secrets: Secrets | null,\n  workflowUid?: string,\n  callbackUrl?: string,\n) => {\n  if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {\n    throw new Error(\n      'The Smartling adapter requires a project ID, a secret key, and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n\n  const accessToken = await authenticate(secrets)\n\n  let taskId = await findExistingJob(document.name, secrets, accessToken)\n  if (!taskId) {\n    taskId = await createJob(document.name, secrets, localeIds, accessToken, documentId)\n  }\n\n  const batchUid = await createJobBatch(\n    taskId,\n    secrets,\n    documentId,\n    accessToken,\n    localeIds,\n    workflowUid,\n  )\n  await uploadFileToBatch(\n    batchUid,\n    documentId,\n    document,\n    secrets,\n    localeIds,\n    accessToken,\n    callbackUrl,\n  )\n\n  return getTranslationTask(documentId, secrets)\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {authenticate, getHeaders} from './helpers'\n\nexport const getLocales: Adapter['getLocales'] = async (secrets: Secrets | null) => {\n  if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {\n    return []\n  }\n  const {project, proxy} = secrets\n  const url = `https://api.smartling.com/projects-api/v2/projects/${project}`\n  const accessToken = await authenticate(secrets)\n  return fetch(proxy, {\n    method: 'GET',\n    headers: getHeaders(url, accessToken),\n  })\n    .then((res) => res.json())\n    .then((res) => res.response.data.targetLocales)\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {authenticate, getHeaders} from './helpers'\n\nexport const getTranslation: Adapter['getTranslation'] = async (\n  taskId: string,\n  localeId: string,\n  secrets: Secrets | null,\n) => {\n  if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {\n    throw new Error(\n      'The Smartling adapter requires a project ID, a secret key, and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n\n  const {project, proxy} = secrets\n\n  const url = `https://api.smartling.com/files-api/v2/projects/${project}/locales/${localeId}/file?fileUri=${taskId}&retrievalType=pending`\n  const accessToken = await authenticate(secrets)\n  const translatedHTML = await fetch(proxy, {\n    method: 'GET',\n    headers: getHeaders(url, accessToken),\n  })\n    .then((res) => res.json())\n    .then((res) => {\n      if (res.body) {\n        return res.body\n      } else if (res.response?.errors) {\n        const errMsg =\n          res.response.errors[0]?.message || 'Error retrieving translation from Smartling'\n        throw new Error(errMsg)\n      }\n      return ''\n    })\n\n  return translatedHTML\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 SmartlingAdapter: Adapter = {\n  getLocales,\n  getTranslationTask,\n  createTask,\n  getTranslation,\n}\n","import {\n  baseDocumentLevelConfig,\n  baseFieldLevelConfig,\n  legacyDocumentLevelConfig as baseLegacyDocumentLevelConfig,\n} from 'sanity-translations-tab'\nimport type {TranslationsTabConfigOptions} from 'sanity-translations-tab'\n\nimport {SmartlingAdapter} from './adapter'\n\nexport {\n  BaseDocumentDeserializer,\n  BaseDocumentMerger,\n  BaseDocumentSerializer,\n  customSerializers,\n  defaultStopTypes,\n  documentLevelPatch,\n  fieldLevelPatch,\n  findLatestDraft,\n  legacyDocumentLevelPatch,\n  TranslationsTab,\n} from 'sanity-translations-tab'\nexport type {\n  TranslationFunctionContext,\n  TranslationsTabConfigOptions,\n} from 'sanity-translations-tab'\n\nconst defaultDocumentLevelConfig: TranslationsTabConfigOptions = {\n  ...baseDocumentLevelConfig,\n  adapter: SmartlingAdapter,\n}\n\nconst legacyDocumentLevelConfig: TranslationsTabConfigOptions = {\n  ...baseLegacyDocumentLevelConfig,\n  adapter: SmartlingAdapter,\n}\n\nconst defaultFieldLevelConfig: TranslationsTabConfigOptions = {\n  ...baseFieldLevelConfig,\n  adapter: SmartlingAdapter,\n}\n\nexport {\n  defaultDocumentLevelConfig,\n  defaultFieldLevelConfig,\n  legacyDocumentLevelConfig,\n  SmartlingAdapter,\n}\n"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"index.js","names":["baseLegacyDocumentLevelConfig","\"Authorization\""],"sources":["../src/adapter/helpers.ts","../src/adapter/getTranslationTask.ts","../src/adapter/createTask.ts","../src/adapter/getLocales.ts","../src/adapter/getTranslation.ts","../src/adapter/index.ts","../src/index.ts"],"sourcesContent":["import type {Secrets} from 'sanity-translations-tab'\n\nexport const authenticate = (secrets: Secrets): Promise<string> => {\n  const url = 'https://api.smartling.com/auth-api/v2/authenticate'\n  const headers = {\n    'content-type': 'application/json',\n    'X-URL': url,\n  }\n  const {secret, proxy} = secrets\n  if (!secret || !proxy) {\n    throw new Error(\n      'The Smartling adapter requires a secret key and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n  // `secret` is already a JSON string (e.g. `{\"userIdentifier\":\"…\",\"userSecret\":\"…\"}`),\n  // so it is sent as-is. Wrapping it in `JSON.stringify` would double-encode it into a\n  // quoted string and break authentication with proxies that forward the body verbatim.\n  return fetch(proxy, {\n    headers,\n    method: 'POST',\n    body: secret,\n  })\n    .then((res) => res.json())\n    .then((res) => {\n      const accessToken = res?.response?.data?.accessToken\n      if (!accessToken) {\n        const errMsg =\n          res?.response?.errors?.[0]?.message ||\n          'Could not authenticate with Smartling. Please check your secret key and proxy URL, per the plugin documentation.'\n        throw new Error(errMsg)\n      }\n      return accessToken\n    })\n}\n\nexport const getHeaders = (url: string, accessToken: string): Record<string, string> => ({\n  'Authorization': `Bearer ${accessToken}`,\n  'X-URL': url,\n})\n\nexport const findExistingJob = async (\n  documentId: string,\n  secrets: Secrets,\n  accessToken: string,\n): Promise<string> => {\n  const {project, proxy} = secrets\n  if (!project || !proxy) {\n    throw new Error(\n      'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n  const url = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs?jobName=${documentId}`\n  //first, try fetching from name resolution\n  let items = await fetch(proxy, {\n    headers: getHeaders(url, accessToken),\n  })\n    .then((res) => res.json())\n    .then((res) => res?.response?.data?.items)\n\n  if (!items || !items.length) {\n    //if that fails, try fetching by fileUri and check the referenceNumber\n    const refUrl = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs/search`\n    items = await fetch(proxy, {\n      headers: {\n        ...getHeaders(refUrl, accessToken),\n        'content-type': 'application/json',\n      },\n      method: 'POST',\n      body: JSON.stringify({\n        fileUris: [documentId],\n      }),\n    })\n      .then((res) => res.json())\n      .then((res) => res?.response?.data?.items)\n  }\n\n  if (items?.length) {\n    //smartling will fuzzy match job names. We need to be precise.\n    const correctJob = items\n      .filter((item: {jobStatus: string}) => item.jobStatus !== 'DELETED')\n      .find(\n        (item: {jobName: string; referenceNumber: string}) =>\n          (item.jobName && item.jobName === documentId) ||\n          (item.referenceNumber && item.referenceNumber === documentId),\n      )\n\n    if (correctJob) {\n      return correctJob.translationJobUid\n    }\n  }\n  return ''\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {authenticate, getHeaders, findExistingJob} from './helpers'\n\ninterface WorkflowProgressItem {\n  workflowStepSummaryReportItemList: {\n    wordCount: number\n  }[]\n}\n\ninterface SmartlingProgressItem {\n  targetLocaleId: string\n  progress: {\n    percentComplete: number\n    totalWordCount: number\n  }\n  workflowProgressReportList: WorkflowProgressItem[]\n}\n\nexport const getTranslationTask: Adapter['getTranslationTask'] = async (\n  documentId: string,\n  secrets: Secrets | null,\n) => {\n  if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {\n    return {\n      documentId,\n      taskId: documentId,\n      locales: [],\n    }\n  }\n\n  const {project, proxy} = secrets\n\n  const accessToken = await authenticate(secrets)\n  const taskId = await findExistingJob(documentId, secrets, accessToken)\n  if (!taskId) {\n    return {\n      documentId,\n      taskId: documentId,\n      locales: [],\n    }\n  }\n\n  const progressUrl = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs/${taskId}/progress`\n  const smartlingTask = await fetch(proxy, {\n    method: 'GET',\n    headers: getHeaders(progressUrl, accessToken),\n  })\n    .then((res) => res.json())\n    .then((res) => res.response.data)\n\n  let locales = []\n  if (smartlingTask && smartlingTask.contentProgressReport) {\n    locales = smartlingTask.contentProgressReport.map((item: SmartlingProgressItem) => {\n      let progress = item.progress ? item.progress.percentComplete : 0\n      //default to the first workflow -- it's likely what is being used\n      const progressItem = item.workflowProgressReportList?.[0]\n      if (progressItem && item.progress) {\n        //this is a list of the various steps in the workflow\n        if (\n          progressItem.workflowStepSummaryReportItemList &&\n          progressItem.workflowStepSummaryReportItemList.length > 1\n        ) {\n          //get the last step in the workflow -- usually \"published\"\n          const lastStep = progressItem.workflowStepSummaryReportItemList.at(-1)\n          //get the percentage of how many words have reached the last step\n          //guard against a 0 totalWordCount (e.g. empty documents) which would\n          //otherwise produce NaN/Infinity and surface as an invalid percentage\n          if (lastStep && lastStep.wordCount >= 0 && item.progress.totalWordCount > 0) {\n            progress = Math.floor((lastStep.wordCount / item.progress.totalWordCount) * 100)\n          }\n        }\n      }\n      return {\n        localeId: item.targetLocaleId,\n        progress,\n      }\n    })\n  }\n\n  return {\n    documentId,\n    locales,\n    //since our download is tied to document id for smartling, keep track of it as a task\n    taskId: documentId,\n    linkToVendorTask: `https://dashboard.smartling.com/app/projects/${project}/account-jobs/${project}:${taskId}`,\n  }\n}\n","import type {Adapter, Secrets, SerializedDocument} from 'sanity-translations-tab'\n\nimport {getTranslationTask} from './getTranslationTask'\nimport {authenticate, getHeaders, findExistingJob} from './helpers'\n\nconst createJob = (\n  jobName: string,\n  secrets: Secrets,\n  localeIds: string[],\n  accessToken: string,\n  documentId: string,\n) => {\n  const {project, proxy} = secrets\n  if (!project || !proxy) {\n    throw new Error(\n      'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n\n  const url = `https://api.smartling.com/jobs-api/v3/projects/${project}/jobs`\n  return fetch(proxy, {\n    method: 'POST',\n    headers: {\n      ...getHeaders(url, accessToken),\n      'content-type': 'application/json',\n    },\n    body: JSON.stringify({\n      jobName,\n      targetLocaleIds: localeIds,\n      referenceNumber: documentId,\n    }),\n  })\n    .then((res) => res.json())\n    .then((res) => res.response.data.translationJobUid)\n}\n\n/* we're using batches here because it eliminates some\n * new string authorization issues for updating existing jobs,\n * and is able to be used for new bulk\n * job functionality.\n */\n\nconst createJobBatch = (\n  jobId: string,\n  secrets: Secrets,\n  documentId: string,\n  accessToken: string,\n  localeIds: string[],\n  workflowUid?: string,\n) => {\n  const {project, proxy} = secrets\n  if (!project || !proxy) {\n    throw new Error(\n      'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n  const url = `https://api.smartling.com/job-batches-api/v2/projects/${project}/batches`\n  const reqBody: {\n    authorize: boolean\n    translationJobUid: string\n    fileUris: string[]\n    localeWorkflows?: {targetLocaleId: string; workflowUid: string}[]\n  } = {\n    authorize: true,\n    translationJobUid: jobId,\n    fileUris: [documentId],\n  }\n\n  if (workflowUid) {\n    reqBody.localeWorkflows = localeIds.map((l) => ({\n      targetLocaleId: l,\n      workflowUid,\n    }))\n  }\n\n  return fetch(proxy, {\n    method: 'POST',\n    headers: {\n      ...getHeaders(url, accessToken),\n      'content-type': 'application/json',\n    },\n    body: JSON.stringify(reqBody),\n  })\n    .then((res) => res.json())\n    .then((res) => res.response.data.batchUid)\n}\n\nconst uploadFileToBatch = (\n  batchUid: string,\n  documentId: string,\n  document: SerializedDocument,\n  secrets: Secrets,\n  localeIds: string[],\n  accessToken: string,\n  callbackUrl?: string,\n) => {\n  const {project, proxy} = secrets\n  if (!project || !proxy) {\n    throw new Error(\n      'The Smartling adapter requires a Smartling project identifier and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n  const url = `https://api.smartling.com/job-batches-api/v2/projects/${project}/batches/${batchUid}/file`\n  const formData = new FormData()\n  formData.append('fileUri', documentId)\n  formData.append('fileType', 'html')\n  formData.append('file', new Blob([document.content]), `${document.name}.html`)\n  localeIds.forEach((localeId) => formData.append('localeIdsToAuthorize[]', localeId))\n  if (callbackUrl) {\n    formData.append('callbackUrl', callbackUrl)\n  }\n\n  return fetch(proxy, {\n    method: 'POST',\n    headers: getHeaders(url, accessToken),\n    body: formData,\n  }).then((res) => res.json())\n}\n\nexport const createTask: Adapter['createTask'] = async (\n  documentId: string,\n  document: SerializedDocument,\n  localeIds: string[],\n  secrets: Secrets | null,\n  workflowUid?: string,\n  callbackUrl?: string,\n) => {\n  if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {\n    throw new Error(\n      'The Smartling adapter requires a project ID, a secret key, and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n\n  const accessToken = await authenticate(secrets)\n\n  let taskId = await findExistingJob(document.name, secrets, accessToken)\n  if (!taskId) {\n    taskId = await createJob(document.name, secrets, localeIds, accessToken, documentId)\n  }\n\n  const batchUid = await createJobBatch(\n    taskId,\n    secrets,\n    documentId,\n    accessToken,\n    localeIds,\n    workflowUid,\n  )\n  await uploadFileToBatch(\n    batchUid,\n    documentId,\n    document,\n    secrets,\n    localeIds,\n    accessToken,\n    callbackUrl,\n  )\n\n  return getTranslationTask(documentId, secrets)\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {authenticate, getHeaders} from './helpers'\n\nexport const getLocales: Adapter['getLocales'] = async (secrets: Secrets | null) => {\n  if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {\n    return []\n  }\n  const {project, proxy} = secrets\n  const url = `https://api.smartling.com/projects-api/v2/projects/${project}`\n  const accessToken = await authenticate(secrets)\n  return fetch(proxy, {\n    method: 'GET',\n    headers: getHeaders(url, accessToken),\n  })\n    .then((res) => res.json())\n    .then((res) => res.response.data.targetLocales)\n}\n","import type {Adapter, Secrets} from 'sanity-translations-tab'\n\nimport {authenticate, getHeaders} from './helpers'\n\nexport const getTranslation: Adapter['getTranslation'] = async (\n  taskId: string,\n  localeId: string,\n  secrets: Secrets | null,\n) => {\n  if (!secrets?.project || !secrets?.secret || !secrets?.proxy) {\n    throw new Error(\n      'The Smartling adapter requires a project ID, a secret key, and a proxy URL. Please check your secrets document in this dataset, per the plugin documentation.',\n    )\n  }\n\n  const {project, proxy} = secrets\n\n  const url = `https://api.smartling.com/files-api/v2/projects/${project}/locales/${localeId}/file?fileUri=${taskId}&retrievalType=pending`\n  const accessToken = await authenticate(secrets)\n  const translatedHTML = await fetch(proxy, {\n    method: 'GET',\n    headers: getHeaders(url, accessToken),\n  })\n    .then((res) => res.json())\n    .then((res) => {\n      if (res.body) {\n        return res.body\n      } else if (res.response?.errors) {\n        const errMsg =\n          res.response.errors[0]?.message || 'Error retrieving translation from Smartling'\n        throw new Error(errMsg)\n      }\n      return ''\n    })\n\n  return translatedHTML\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 SmartlingAdapter: Adapter = {\n  getLocales,\n  getTranslationTask,\n  createTask,\n  getTranslation,\n}\n","import {\n  baseDocumentLevelConfig,\n  baseFieldLevelConfig,\n  legacyDocumentLevelConfig as baseLegacyDocumentLevelConfig,\n} from 'sanity-translations-tab'\nimport type {TranslationsTabConfigOptions} from 'sanity-translations-tab'\n\nimport {SmartlingAdapter} from './adapter'\n\nexport {\n  BaseDocumentDeserializer,\n  BaseDocumentMerger,\n  BaseDocumentSerializer,\n  customSerializers,\n  defaultStopTypes,\n  documentLevelPatch,\n  fieldLevelPatch,\n  findLatestDraft,\n  legacyDocumentLevelPatch,\n  TranslationsTab,\n} from 'sanity-translations-tab'\nexport type {\n  TranslationFunctionContext,\n  TranslationsTabConfigOptions,\n} from 'sanity-translations-tab'\n\nconst defaultDocumentLevelConfig: TranslationsTabConfigOptions = {\n  ...baseDocumentLevelConfig,\n  adapter: SmartlingAdapter,\n}\n\nconst legacyDocumentLevelConfig: TranslationsTabConfigOptions = {\n  ...baseLegacyDocumentLevelConfig,\n  adapter: SmartlingAdapter,\n}\n\nconst defaultFieldLevelConfig: TranslationsTabConfigOptions = {\n  ...baseFieldLevelConfig,\n  adapter: SmartlingAdapter,\n}\n\nexport {\n  defaultDocumentLevelConfig,\n  defaultFieldLevelConfig,\n  legacyDocumentLevelConfig,\n  SmartlingAdapter,\n}\n"],"mappings":";AAEA,MAAa,gBAAgB,YAAsC;CAEjE,IAAM,UAAU;EACd,gBAAgB;EAChB,SAAS;CACX,GACM,EAAC,QAAQ,UAAS;CACxB,IAAI,CAAC,UAAU,CAAC,OACd,MAAU,MACR,gJACF;CAKF,OAAO,MAAM,OAAO;EAClB;EACA,QAAQ;EACR,MAAM;CACR,CAAC,CAAC,CACC,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CACzB,MAAM,QAAQ;EACb,IAAM,cAAc,KAAK,UAAU,MAAM;EACzC,IAAI,CAAC,aAAa;GAChB,IAAM,SACJ,KAAK,UAAU,SAAS,EAAE,EAAE,WAC5B;GACF,MAAU,MAAM,MAAM;EACxB;EACA,OAAO;CACT,CAAC;AACL,GAEa,cAAc,KAAa,iBAAiD;CACvFC,eAAiB,UAAU;CAC3B,SAAS;AACX,IAEa,kBAAkB,OAC7B,YACA,SACA,gBACoB;CACpB,IAAM,EAAC,SAAS,UAAS;CACzB,IAAI,CAAC,WAAW,CAAC,OACf,MAAU,MACR,kKACF;CAEF,IAAM,MAAM,kDAAkD,QAAQ,gBAAgB,cAElF,QAAQ,MAAM,MAAM,OAAO,EAC7B,SAAS,WAAW,KAAK,WAAW,EACtC,CAAC,CAAC,CACC,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CACzB,MAAM,QAAQ,KAAK,UAAU,MAAM,KAAK;CAE3C,IAAI,CAAC,SAAS,CAAC,MAAM,QAAQ;EAE3B,IAAM,SAAS,kDAAkD,QAAQ;EACzE,QAAQ,MAAM,MAAM,OAAO;GACzB,SAAS;IACP,GAAG,WAAW,QAAQ,WAAW;IACjC,gBAAgB;GAClB;GACA,QAAQ;GACR,MAAM,KAAK,UAAU,EACnB,UAAU,CAAC,UAAU,EACvB,CAAC;EACH,CAAC,CAAC,CACC,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CACzB,MAAM,QAAQ,KAAK,UAAU,MAAM,KAAK;CAC7C;CAEA,IAAI,OAAO,QAAQ;EAEjB,IAAM,aAAa,MAChB,QAAQ,SAA8B,KAAK,cAAc,SAAS,CAAC,CACnE,MACE,SACE,KAAK,WAAW,KAAK,YAAY,cACjC,KAAK,mBAAmB,KAAK,oBAAoB,UACtD;EAEF,IAAI,YACF,OAAO,WAAW;CAEtB;CACA,OAAO;AACT,GCxEa,qBAAoD,OAC/D,YACA,YACG;CACH,IAAI,CAAC,SAAS,WAAW,CAAC,SAAS,UAAU,CAAC,SAAS,OACrD,OAAO;EACL;EACA,QAAQ;EACR,SAAS,CAAC;CACZ;CAGF,IAAM,EAAC,SAAS,UAAS,SAEnB,cAAc,MAAM,aAAa,OAAO,GACxC,SAAS,MAAM,gBAAgB,YAAY,SAAS,WAAW;CACrE,IAAI,CAAC,QACH,OAAO;EACL;EACA,QAAQ;EACR,SAAS,CAAC;CACZ;CAGF,IAAM,cAAc,kDAAkD,QAAQ,QAAQ,OAAO,YACvF,gBAAgB,MAAM,MAAM,OAAO;EACvC,QAAQ;EACR,SAAS,WAAW,aAAa,WAAW;CAC9C,CAAC,CAAC,CACC,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CACzB,MAAM,QAAQ,IAAI,SAAS,IAAI,GAE9B,UAAU,CAAC;CA6Bf,OA5BI,iBAAiB,cAAc,0BACjC,UAAU,cAAc,sBAAsB,KAAK,SAAgC;EACjF,IAAI,WAAW,KAAK,WAAW,KAAK,SAAS,kBAAkB,GAEzD,eAAe,KAAK,6BAA6B;EACvD,IAAI,gBAAgB,KAAK,YAGrB,aAAa,qCACb,aAAa,kCAAkC,SAAS,GACxD;GAEA,IAAM,WAAW,aAAa,kCAAkC,GAAG,EAAE;GAIrE,AAAI,YAAY,SAAS,aAAa,KAAK,KAAK,SAAS,iBAAiB,MACxE,WAAW,KAAK,MAAO,SAAS,YAAY,KAAK,SAAS,iBAAkB,GAAG;EAEnF;EAEF,OAAO;GACL,UAAU,KAAK;GACf;EACF;CACF,CAAC,IAGI;EACL;EACA;EAEA,QAAQ;EACR,kBAAkB,gDAAgD,QAAQ,gBAAgB,QAAQ,GAAG;CACvG;AACF,GClFM,aACJ,SACA,SACA,WACA,aACA,eACG;CACH,IAAM,EAAC,SAAS,UAAS;CACzB,IAAI,CAAC,WAAW,CAAC,OACf,MAAU,MACR,kKACF;CAGF,IAAM,MAAM,kDAAkD,QAAQ;CACtE,OAAO,MAAM,OAAO;EAClB,QAAQ;EACR,SAAS;GACP,GAAG,WAAW,KAAK,WAAW;GAC9B,gBAAgB;EAClB;EACA,MAAM,KAAK,UAAU;GACnB;GACA,iBAAiB;GACjB,iBAAiB;EACnB,CAAC;CACH,CAAC,CAAC,CACC,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CACzB,MAAM,QAAQ,IAAI,SAAS,KAAK,iBAAiB;AACtD,GAQM,kBACJ,OACA,SACA,YACA,aACA,WACA,gBACG;CACH,IAAM,EAAC,SAAS,UAAS;CACzB,IAAI,CAAC,WAAW,CAAC,OACf,MAAU,MACR,kKACF;CAEF,IAAM,MAAM,yDAAyD,QAAQ,WACvE,UAKF;EACF,WAAW;EACX,mBAAmB;EACnB,UAAU,CAAC,UAAU;CACvB;CASA,OAPI,gBACF,QAAQ,kBAAkB,UAAU,KAAK,OAAO;EAC9C,gBAAgB;EAChB;CACF,EAAE,IAGG,MAAM,OAAO;EAClB,QAAQ;EACR,SAAS;GACP,GAAG,WAAW,KAAK,WAAW;GAC9B,gBAAgB;EAClB;EACA,MAAM,KAAK,UAAU,OAAO;CAC9B,CAAC,CAAC,CACC,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CACzB,MAAM,QAAQ,IAAI,SAAS,KAAK,QAAQ;AAC7C,GAEM,qBACJ,UACA,YACA,UACA,SACA,WACA,aACA,gBACG;CACH,IAAM,EAAC,SAAS,UAAS;CACzB,IAAI,CAAC,WAAW,CAAC,OACf,MAAU,MACR,kKACF;CAEF,IAAM,MAAM,yDAAyD,QAAQ,WAAW,SAAS,QAC3F,WAAW,IAAI,SAAS;CAS9B,OARA,SAAS,OAAO,WAAW,UAAU,GACrC,SAAS,OAAO,YAAY,MAAM,GAClC,SAAS,OAAO,QAAQ,IAAI,KAAK,CAAC,SAAS,OAAO,CAAC,GAAG,GAAG,SAAS,KAAK,MAAM,GAC7E,UAAU,SAAS,aAAa,SAAS,OAAO,0BAA0B,QAAQ,CAAC,GAC/E,eACF,SAAS,OAAO,eAAe,WAAW,GAGrC,MAAM,OAAO;EAClB,QAAQ;EACR,SAAS,WAAW,KAAK,WAAW;EACpC,MAAM;CACR,CAAC,CAAC,CAAC,MAAM,QAAQ,IAAI,KAAK,CAAC;AAC7B,GAEa,aAAoC,OAC/C,YACA,UACA,WACA,SACA,aACA,gBACG;CACH,IAAI,CAAC,SAAS,WAAW,CAAC,SAAS,UAAU,CAAC,SAAS,OACrD,MAAU,MACR,+JACF;CAGF,IAAM,cAAc,MAAM,aAAa,OAAO,GAE1C,SAAS,MAAM,gBAAgB,SAAS,MAAM,SAAS,WAAW;CACtE,AACE,WAAS,MAAM,UAAU,SAAS,MAAM,SAAS,WAAW,aAAa,UAAU;CAGrF,IAAM,WAAW,MAAM,eACrB,QACA,SACA,YACA,aACA,WACA,WACF;CAWA,OAVA,MAAM,kBACJ,UACA,YACA,UACA,SACA,WACA,aACA,WACF,GAEO,mBAAmB,YAAY,OAAO;AAC/C,GC3Ja,aAAoC,OAAO,YAA4B;CAClF,IAAI,CAAC,SAAS,WAAW,CAAC,SAAS,UAAU,CAAC,SAAS,OACrD,OAAO,CAAC;CAEV,IAAM,EAAC,SAAS,UAAS,SACnB,MAAM,sDAAsD,WAC5D,cAAc,MAAM,aAAa,OAAO;CAC9C,OAAO,MAAM,OAAO;EAClB,QAAQ;EACR,SAAS,WAAW,KAAK,WAAW;CACtC,CAAC,CAAC,CACC,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CACzB,MAAM,QAAQ,IAAI,SAAS,KAAK,aAAa;AAClD,GCba,iBAA4C,OACvD,QACA,UACA,YACG;CACH,IAAI,CAAC,SAAS,WAAW,CAAC,SAAS,UAAU,CAAC,SAAS,OACrD,MAAU,MACR,+JACF;CAGF,IAAM,EAAC,SAAS,UAAS,SAEnB,MAAM,mDAAmD,QAAQ,WAAW,SAAS,gBAAgB,OAAO,yBAC5G,cAAc,MAAM,aAAa,OAAO;CAiB9C,OAAO,MAhBsB,MAAM,OAAO;EACxC,QAAQ;EACR,SAAS,WAAW,KAAK,WAAW;CACtC,CAAC,CAAC,CACC,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,CACzB,MAAM,QAAQ;EACb,IAAI,IAAI,MACN,OAAO,IAAI;EACN,IAAI,IAAI,UAAU,QAAQ;GAC/B,IAAM,SACJ,IAAI,SAAS,OAAO,EAAE,EAAE,WAAW;GACrC,MAAU,MAAM,MAAM;EACxB;EACA,OAAO;CACT,CAAC;AAGL,GC7Ba,mBAA4B;CACvC;CACA;CACA;CACA;AACF,GCcM,6BAA2D;CAC/D,GAAG;CACH,SAAS;AACX,GAEM,4BAA0D;CAC9D,GAAGD;CACH,SAAS;AACX,GAEM,0BAAwD;CAC5D,GAAG;CACH,SAAS;AACX"}
\ No newline at end of file