sanity-plugin-studio-smartling
5.0.75.0.8
~
Modified (4 files)
Index: package/dist/index.js
===================================================================
--- package/dist/index.js
+++ package/dist/index.js
@@ -121,9 +121,11 @@
getTranslationTask,
createTask: async (documentId, document, localeIds, secrets, workflowUid, callbackUrl) => {
if (!secrets?.project || !secrets?.secret || !secrets?.proxy) throw Error("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.");
let accessToken = await authenticate(secrets), taskId = await findExistingJob(document.name, secrets, accessToken);
- return taskId ||= await createJob(document.name, secrets, localeIds, accessToken, documentId), await uploadFileToBatch(await createJobBatch(taskId, secrets, documentId, accessToken, localeIds, workflowUid), documentId, document, secrets, localeIds, accessToken, callbackUrl), getTranslationTask(documentId, secrets);
+ taskId ||= await createJob(document.name, secrets, localeIds, accessToken, documentId);
+ let batchUid = await createJobBatch(taskId, secrets, documentId, accessToken, localeIds, workflowUid);
+ return await uploadFileToBatch(batchUid, documentId, document, secrets, localeIds, accessToken, callbackUrl), getTranslationTask(documentId, secrets);
},
getTranslation: async (taskId, localeId, secrets) => {
if (!secrets?.project || !secrets?.secret || !secrets?.proxy) throw Error("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.");
let { project, proxy } = secrets, url = `https://api.smartling.com/files-api/v2/projects/${project}/locales/${localeId}/file?fileUri=${taskId}&retrievalType=pending`, accessToken = await authenticate(secrets); Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,7 +1,7 @@
{
"name": "sanity-plugin-studio-smartling",
- "version": "5.0.7",
+ "version": "5.0.8",
"description": "This plugin provides an in-studio integration with Smartling. It allows your editors to send any document to Smartling 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/adapter/index.ts","../src/index.ts"],"mappings":";cAOa,gBAAA,EAAkB,OAK9B;AAAA,cCcK,0BAAA,EAA4B,8BAGjC;AAAA,cAEK,yBAAA,EAA2B,8BAGhC;AAAA,cAEK,uBAAA,EAAyB,8BAG9B"}
\ No newline at end of file
+{"version":3,"file":"index.d.ts","names":[],"sources":["../src/adapter/index.ts","../src/index.ts"],"mappings":";cAOa,kBAAkB;cCmBzB,4BAA4B;cAK5B,2BAA2B;cAK3B,yBAAyB"}
\ 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","authenticate","secrets","Promise","url","headers","secret","proxy","Error","fetch","method","body","JSON","stringify","then","res","json","response","data","accessToken","getHeaders","Record","findExistingJob","documentId","project","items","length","refUrl","fileUris","correctJob","filter","item","jobStatus","find","jobName","referenceNumber","translationJobUid","Adapter","Secrets","authenticate","getHeaders","findExistingJob","WorkflowProgressItem","workflowStepSummaryReportItemList","wordCount","SmartlingProgressItem","targetLocaleId","progress","percentComplete","totalWordCount","workflowProgressReportList","getTranslationTask","documentId","secrets","project","secret","proxy","taskId","locales","accessToken","progressUrl","smartlingTask","fetch","method","headers","then","res","json","response","data","contentProgressReport","map","item","progressItem","length","lastStep","at","Math","floor","localeId","linkToVendorTask","Adapter","Secrets","SerializedDocument","getTranslationTask","authenticate","getHeaders","findExistingJob","createJob","jobName","secrets","localeIds","accessToken","documentId","project","proxy","Error","url","fetch","method","headers","body","JSON","stringify","targetLocaleIds","referenceNumber","then","res","json","response","data","translationJobUid","createJobBatch","jobId","workflowUid","reqBody","authorize","fileUris","localeWorkflows","targetLocaleId","map","l","batchUid","uploadFileToBatch","document","callbackUrl","formData","FormData","append","Blob","content","name","forEach","localeId","createTask","secret","taskId","Adapter","Secrets","authenticate","getHeaders","getLocales","secrets","project","secret","proxy","url","accessToken","fetch","method","headers","then","res","json","response","data","targetLocales","Adapter","Secrets","authenticate","getHeaders","getTranslation","taskId","localeId","secrets","project","secret","proxy","Error","url","accessToken","translatedHTML","fetch","method","headers","then","res","json","body","response","errors","errMsg","message","Adapter","createTask","getLocales","getTranslation","getTranslationTask","SmartlingAdapter","baseLegacyDocumentLevelConfig"],"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 return fetch(proxy, {\n headers,\n method: 'POST',\n body: JSON.stringify(secret),\n })\n .then((res) => res.json())\n .then((res) => res.response.data.accessToken)\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 if (lastStep && lastStep.wordCount >= 0) {\n progress = Math.floor((lastStep.wordCount / item.progress.totalWordCount) * 100) ?? 0\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":["Secrets","authenticate","secrets","Promise","url","headers","secret","proxy","Error","fetch","method","body","JSON","stringify","then","res","json","response","data","accessToken","getHeaders","Record","findExistingJob","documentId","project","items","length","refUrl","fileUris","correctJob","filter","item","jobStatus","find","jobName","referenceNumber","translationJobUid","Adapter","Secrets","authenticate","getHeaders","findExistingJob","WorkflowProgressItem","workflowStepSummaryReportItemList","wordCount","SmartlingProgressItem","targetLocaleId","progress","percentComplete","totalWordCount","workflowProgressReportList","getTranslationTask","documentId","secrets","project","secret","proxy","taskId","locales","accessToken","progressUrl","smartlingTask","fetch","method","headers","then","res","json","response","data","contentProgressReport","map","item","progressItem","length","lastStep","at","Math","floor","localeId","linkToVendorTask","Adapter","Secrets","SerializedDocument","getTranslationTask","authenticate","getHeaders","findExistingJob","createJob","jobName","secrets","localeIds","accessToken","documentId","project","proxy","Error","url","fetch","method","headers","body","JSON","stringify","targetLocaleIds","referenceNumber","then","res","json","response","data","translationJobUid","createJobBatch","jobId","workflowUid","reqBody","authorize","fileUris","localeWorkflows","targetLocaleId","map","l","batchUid","uploadFileToBatch","document","callbackUrl","formData","FormData","append","Blob","content","name","forEach","localeId","createTask","secret","taskId","Adapter","Secrets","authenticate","getHeaders","getLocales","secrets","project","secret","proxy","url","accessToken","fetch","method","headers","then","res","json","response","data","targetLocales","Adapter","Secrets","authenticate","getHeaders","getTranslation","taskId","localeId","secrets","project","secret","proxy","Error","url","accessToken","translatedHTML","fetch","method","headers","then","res","json","body","response","errors","errMsg","message","Adapter","createTask","getLocales","getTranslation","getTranslationTask","SmartlingAdapter","baseLegacyDocumentLevelConfig"],"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 return fetch(proxy, {\n headers,\n method: 'POST',\n body: JSON.stringify(secret),\n })\n .then((res) => res.json())\n .then((res) => res.response.data.accessToken)\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 if (lastStep && lastStep.wordCount >= 0) {\n progress = Math.floor((lastStep.wordCount / item.progress.totalWordCount) * 100) ?? 0\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