smartling-api-sdk-nodejs 3.3.0 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +1 -1
- package/api/glossaries/params/create-glossary-parameters.ts +0 -6
- package/api/translation-memory/dto/async-action-result-dto.ts +12 -0
- package/api/translation-memory/dto/async-action-status.ts +8 -0
- package/api/translation-memory/dto/create-string-search-result-dto.ts +16 -0
- package/api/translation-memory/dto/duplicate-string-dto.ts +9 -0
- package/api/translation-memory/dto/locale-summary-dto.ts +10 -0
- package/api/translation-memory/dto/strings-export-async-action-result-dto.ts +8 -0
- package/api/translation-memory/dto/tm-dto.ts +23 -0
- package/api/translation-memory/dto/tm-locale-dto.ts +8 -0
- package/api/translation-memory/dto/tmx-import-summary-dto.ts +16 -0
- package/api/translation-memory/dto/tmx-parsing-error-dto.ts +7 -0
- package/api/translation-memory/dto/user-dto.ts +6 -0
- package/api/translation-memory/index.ts +368 -0
- package/api/translation-memory/params/bulk-export-tm-strings-parameters.ts +30 -0
- package/api/translation-memory/params/create-string-search-filter-parameters.ts +232 -0
- package/api/translation-memory/params/create-string-search-options.ts +8 -0
- package/api/translation-memory/params/create-tm-parameters.ts +28 -0
- package/api/translation-memory/params/escape-smp-unicode-parser-directive.ts +6 -0
- package/api/translation-memory/params/extended-export-metadata-type.ts +4 -0
- package/api/translation-memory/params/import-tmx-file-parameters.ts +76 -0
- package/api/translation-memory/params/keyword-search-type.ts +5 -0
- package/api/translation-memory/params/leverage-type.ts +5 -0
- package/api/translation-memory/params/search-keyword.ts +10 -0
- package/api/translation-memory/params/source-type.ts +7 -0
- package/api/translation-memory/params/string-search-tags.ts +7 -0
- package/api/translation-memory/params/translation-quality-type.ts +5 -0
- package/api/translation-memory/params/tu-translation-quality-type.ts +6 -0
- package/api/translation-memory/params/update-tm-parameters.ts +23 -0
- package/built/api/glossaries/params/create-glossary-parameters.d.ts +0 -1
- package/built/api/glossaries/params/create-glossary-parameters.js +0 -4
- package/built/api/glossaries/params/create-glossary-parameters.js.map +1 -1
- package/built/api/translation-memory/dto/async-action-result-dto.d.ts +10 -0
- package/built/api/translation-memory/dto/async-action-result-dto.js +3 -0
- package/built/api/translation-memory/dto/async-action-result-dto.js.map +1 -0
- package/built/api/translation-memory/dto/async-action-status.d.ts +8 -0
- package/built/api/translation-memory/dto/async-action-status.js +13 -0
- package/built/api/translation-memory/dto/async-action-status.js.map +1 -0
- package/built/api/translation-memory/dto/create-string-search-result-dto.d.ts +11 -0
- package/built/api/translation-memory/dto/create-string-search-result-dto.js +3 -0
- package/built/api/translation-memory/dto/create-string-search-result-dto.js.map +1 -0
- package/built/api/translation-memory/dto/duplicate-string-dto.d.ts +8 -0
- package/built/api/translation-memory/dto/duplicate-string-dto.js +3 -0
- package/built/api/translation-memory/dto/duplicate-string-dto.js.map +1 -0
- package/built/api/translation-memory/dto/locale-summary-dto.d.ts +8 -0
- package/built/api/translation-memory/dto/locale-summary-dto.js +3 -0
- package/built/api/translation-memory/dto/locale-summary-dto.js.map +1 -0
- package/built/api/translation-memory/dto/strings-export-async-action-result-dto.d.ts +6 -0
- package/built/api/translation-memory/dto/strings-export-async-action-result-dto.js +3 -0
- package/built/api/translation-memory/dto/strings-export-async-action-result-dto.js.map +1 -0
- package/built/api/translation-memory/dto/tm-dto.d.ts +19 -0
- package/built/api/translation-memory/dto/tm-dto.js +3 -0
- package/built/api/translation-memory/dto/tm-dto.js.map +1 -0
- package/built/api/translation-memory/dto/tm-locale-dto.d.ts +7 -0
- package/built/api/translation-memory/dto/tm-locale-dto.js +3 -0
- package/built/api/translation-memory/dto/tm-locale-dto.js.map +1 -0
- package/built/api/translation-memory/dto/tmx-import-summary-dto.d.ts +11 -0
- package/built/api/translation-memory/dto/tmx-import-summary-dto.js +3 -0
- package/built/api/translation-memory/dto/tmx-import-summary-dto.js.map +1 -0
- package/built/api/translation-memory/dto/tmx-parsing-error-dto.d.ts +6 -0
- package/built/api/translation-memory/dto/tmx-parsing-error-dto.js +3 -0
- package/built/api/translation-memory/dto/tmx-parsing-error-dto.js.map +1 -0
- package/built/api/translation-memory/dto/user-dto.d.ts +5 -0
- package/built/api/translation-memory/dto/user-dto.js +3 -0
- package/built/api/translation-memory/dto/user-dto.js.map +1 -0
- package/built/api/translation-memory/index.d.ts +27 -0
- package/built/api/translation-memory/index.js +250 -0
- package/built/api/translation-memory/index.js.map +1 -0
- package/built/api/translation-memory/params/bulk-export-tm-strings-parameters.d.ts +8 -0
- package/built/api/translation-memory/params/bulk-export-tm-strings-parameters.js +24 -0
- package/built/api/translation-memory/params/bulk-export-tm-strings-parameters.js.map +1 -0
- package/built/api/translation-memory/params/create-string-search-filter-parameters.d.ts +43 -0
- package/built/api/translation-memory/params/create-string-search-filter-parameters.js +151 -0
- package/built/api/translation-memory/params/create-string-search-filter-parameters.js.map +1 -0
- package/built/api/translation-memory/params/create-string-search-options.d.ts +7 -0
- package/built/api/translation-memory/params/create-string-search-options.js +3 -0
- package/built/api/translation-memory/params/create-string-search-options.js.map +1 -0
- package/built/api/translation-memory/params/create-tm-parameters.d.ts +8 -0
- package/built/api/translation-memory/params/create-tm-parameters.js +24 -0
- package/built/api/translation-memory/params/create-tm-parameters.js.map +1 -0
- package/built/api/translation-memory/params/escape-smp-unicode-parser-directive.d.ts +4 -0
- package/built/api/translation-memory/params/escape-smp-unicode-parser-directive.js +9 -0
- package/built/api/translation-memory/params/escape-smp-unicode-parser-directive.js.map +1 -0
- package/built/api/translation-memory/params/extended-export-metadata-type.d.ts +4 -0
- package/built/api/translation-memory/params/extended-export-metadata-type.js +9 -0
- package/built/api/translation-memory/params/extended-export-metadata-type.js.map +1 -0
- package/built/api/translation-memory/params/import-tmx-file-parameters.d.ts +17 -0
- package/built/api/translation-memory/params/import-tmx-file-parameters.js +80 -0
- package/built/api/translation-memory/params/import-tmx-file-parameters.js.map +1 -0
- package/built/api/translation-memory/params/keyword-search-type.d.ts +5 -0
- package/built/api/translation-memory/params/keyword-search-type.js +10 -0
- package/built/api/translation-memory/params/keyword-search-type.js.map +1 -0
- package/built/api/translation-memory/params/leverage-type.d.ts +5 -0
- package/built/api/translation-memory/params/leverage-type.js +10 -0
- package/built/api/translation-memory/params/leverage-type.js.map +1 -0
- package/built/api/translation-memory/params/search-keyword.d.ts +8 -0
- package/built/api/translation-memory/params/search-keyword.js +3 -0
- package/built/api/translation-memory/params/search-keyword.js.map +1 -0
- package/built/api/translation-memory/params/source-type.d.ts +7 -0
- package/built/api/translation-memory/params/source-type.js +12 -0
- package/built/api/translation-memory/params/source-type.js.map +1 -0
- package/built/api/translation-memory/params/string-search-tags.d.ts +6 -0
- package/built/api/translation-memory/params/string-search-tags.js +3 -0
- package/built/api/translation-memory/params/string-search-tags.js.map +1 -0
- package/built/api/translation-memory/params/translation-quality-type.d.ts +5 -0
- package/built/api/translation-memory/params/translation-quality-type.js +10 -0
- package/built/api/translation-memory/params/translation-quality-type.js.map +1 -0
- package/built/api/translation-memory/params/tu-translation-quality-type.d.ts +6 -0
- package/built/api/translation-memory/params/tu-translation-quality-type.js +11 -0
- package/built/api/translation-memory/params/tu-translation-quality-type.js.map +1 -0
- package/built/api/translation-memory/params/update-tm-parameters.d.ts +6 -0
- package/built/api/translation-memory/params/update-tm-parameters.js +20 -0
- package/built/api/translation-memory/params/update-tm-parameters.js.map +1 -0
- package/built/index.d.ts +27 -0
- package/built/index.js +27 -0
- package/built/index.js.map +1 -1
- package/built/package.json +1 -1
- package/built/test/glossaries.spec.js +2 -4
- package/built/test/glossaries.spec.js.map +1 -1
- package/built/test/integration/translation-memory.spec.d.ts +1 -0
- package/built/test/integration/translation-memory.spec.js +138 -0
- package/built/test/integration/translation-memory.spec.js.map +1 -0
- package/built/test/translation-memory.spec.d.ts +1 -0
- package/built/test/translation-memory.spec.js +712 -0
- package/built/test/translation-memory.spec.js.map +1 -0
- package/index.ts +27 -0
- package/package.json +1 -1
- package/test/data/sample.tmx +12 -0
- package/test/glossaries.spec.ts +2 -4
- package/test/integration/translation-memory.spec.ts +182 -0
- package/test/translation-memory.spec.ts +868 -0
package/.env.example
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Credentials for test/integration/glossaries.spec.ts.
|
|
1
|
+
# Credentials for test/integration/glossaries.spec.ts and test/integration/translation-memory.spec.ts.
|
|
2
2
|
# Copy this file to .env and fill in real values to run: npm run test:integration
|
|
3
3
|
# Without a real .env, the integration suite skips (shows as pending) rather than failing.
|
|
4
4
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AsyncActionStatus } from "./async-action-status";
|
|
2
|
+
|
|
3
|
+
interface AsyncActionResultDto {
|
|
4
|
+
actionUid: string;
|
|
5
|
+
totalCount: number;
|
|
6
|
+
processedCount: number;
|
|
7
|
+
errorCount: number;
|
|
8
|
+
executionComplete: boolean;
|
|
9
|
+
actionStatus: AsyncActionStatus;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { AsyncActionResultDto };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DuplicateStringDto } from "./duplicate-string-dto";
|
|
2
|
+
|
|
3
|
+
interface CreateStringSearchResultDto {
|
|
4
|
+
searchUid: string;
|
|
5
|
+
stringCount: number | null;
|
|
6
|
+
wordCount: number | null;
|
|
7
|
+
duplicateStrings: Array<DuplicateStringDto> | null;
|
|
8
|
+
duplicateSearch: boolean | null;
|
|
9
|
+
// UID of the async action tracking search indexing, only present if indexing continues in
|
|
10
|
+
// the background - distinct from AsyncActionResultDto.actionUid (a bulk operation's own
|
|
11
|
+
// tracking UID, always present once that operation has started).
|
|
12
|
+
actionUid: string | null;
|
|
13
|
+
offlineReportUid: string | null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { CreateStringSearchResultDto };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { UserDto } from "./user-dto";
|
|
2
|
+
import { TmLocaleDto } from "./tm-locale-dto";
|
|
3
|
+
import { LocaleSummaryDto } from "./locale-summary-dto";
|
|
4
|
+
import { TranslationQualityType } from "../params/translation-quality-type";
|
|
5
|
+
|
|
6
|
+
interface TmDto {
|
|
7
|
+
// Nullable per the real schema (TM.tmUid: ID, no "!"), but in practice always populated for
|
|
8
|
+
// a successful createTm/updateTm/deleteTm/searchTms result - it's the TM's own identifier.
|
|
9
|
+
tmUid: string | null;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string | null;
|
|
12
|
+
sourceLocaleId: string;
|
|
13
|
+
sourceLocale: TmLocaleDto;
|
|
14
|
+
creator: UserDto;
|
|
15
|
+
created: Date;
|
|
16
|
+
lastModifier: UserDto;
|
|
17
|
+
lastModified: Date;
|
|
18
|
+
localeSummary: Array<LocaleSummaryDto> | null;
|
|
19
|
+
translationQuality: TranslationQualityType;
|
|
20
|
+
managedWordsEnabled: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { TmDto };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TmxParsingErrorDto } from "./tmx-parsing-error-dto";
|
|
2
|
+
|
|
3
|
+
interface TmxImportSummaryDto {
|
|
4
|
+
message: string | null;
|
|
5
|
+
wordCount: number;
|
|
6
|
+
stringCount: number;
|
|
7
|
+
// Errors rejecting specific translation units from the TM itself (e.g. a business-rule
|
|
8
|
+
// violation on an otherwise well-formed unit).
|
|
9
|
+
translationMemoryImportErrors: Array<TmxParsingErrorDto> | null;
|
|
10
|
+
// Errors in the TMX file's own XML/structure, encountered while parsing it.
|
|
11
|
+
parsingErrors: Array<TmxParsingErrorDto> | null;
|
|
12
|
+
jobUid: string;
|
|
13
|
+
tmxUid: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { TmxImportSummaryDto };
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import FormData from "form-data";
|
|
2
|
+
import { SmartlingBaseFileApi } from "../base";
|
|
3
|
+
import { AccessTokenProvider } from "../auth/access-token-provider";
|
|
4
|
+
import { Logger } from "../logger";
|
|
5
|
+
import { SmartlingException } from "../exception/index";
|
|
6
|
+
import { ResponseBodyType } from "../base/enum/response-body-type";
|
|
7
|
+
import { TranslatedFileDto } from "../dto/translated-file-dto";
|
|
8
|
+
import { ImportTmxFileParameters } from "./params/import-tmx-file-parameters";
|
|
9
|
+
import { TmxImportSummaryDto } from "./dto/tmx-import-summary-dto";
|
|
10
|
+
import { CreateStringSearchFilterParameters } from "./params/create-string-search-filter-parameters";
|
|
11
|
+
import { CreateStringSearchResultDto } from "./dto/create-string-search-result-dto";
|
|
12
|
+
import { BulkExportTmStringsParameters } from "./params/bulk-export-tm-strings-parameters";
|
|
13
|
+
import { AsyncActionResultDto } from "./dto/async-action-result-dto";
|
|
14
|
+
import { StringsExportAsyncActionResultDto } from "./dto/strings-export-async-action-result-dto";
|
|
15
|
+
import { CreateTmParameters } from "./params/create-tm-parameters";
|
|
16
|
+
import { UpdateTmParameters } from "./params/update-tm-parameters";
|
|
17
|
+
import { TmDto } from "./dto/tm-dto";
|
|
18
|
+
|
|
19
|
+
const TM_FIELDS = `
|
|
20
|
+
tmUid
|
|
21
|
+
name
|
|
22
|
+
description
|
|
23
|
+
sourceLocaleId
|
|
24
|
+
sourceLocale {
|
|
25
|
+
localeId
|
|
26
|
+
localeDescription
|
|
27
|
+
rtlLanguage
|
|
28
|
+
wordSpacing
|
|
29
|
+
}
|
|
30
|
+
creator {
|
|
31
|
+
userUid
|
|
32
|
+
name
|
|
33
|
+
}
|
|
34
|
+
created
|
|
35
|
+
lastModifier {
|
|
36
|
+
userUid
|
|
37
|
+
name
|
|
38
|
+
}
|
|
39
|
+
lastModified
|
|
40
|
+
localeSummary {
|
|
41
|
+
translationLocaleId
|
|
42
|
+
translationLocale {
|
|
43
|
+
localeId
|
|
44
|
+
localeDescription
|
|
45
|
+
rtlLanguage
|
|
46
|
+
wordSpacing
|
|
47
|
+
}
|
|
48
|
+
stringCount
|
|
49
|
+
wordCount
|
|
50
|
+
}
|
|
51
|
+
translationQuality
|
|
52
|
+
managedWordsEnabled
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
const CREATE_TM_QUERY = `
|
|
56
|
+
mutation createTm($createTm: CreateTm!) {
|
|
57
|
+
createTm(createTm: $createTm) {
|
|
58
|
+
${TM_FIELDS}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
const UPDATE_TM_QUERY = `
|
|
64
|
+
mutation updateTm($updateTm: UpdateTm!) {
|
|
65
|
+
updateTm(updateTm: $updateTm) {
|
|
66
|
+
${TM_FIELDS}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
const DELETE_TM_QUERY = `
|
|
72
|
+
mutation deleteTm($deleteTm: DeleteTm!) {
|
|
73
|
+
deleteTm(deleteTm: $deleteTm) {
|
|
74
|
+
${TM_FIELDS}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
const CREATE_STRING_SEARCH_QUERY = `
|
|
80
|
+
mutation createStringSearch($createStringSearchFilter: CreateStringSearchFilter!) {
|
|
81
|
+
createStringSearch(createStringSearchFilter: $createStringSearchFilter) {
|
|
82
|
+
searchUid
|
|
83
|
+
stringCount
|
|
84
|
+
wordCount
|
|
85
|
+
duplicateStrings {
|
|
86
|
+
duplicateKey
|
|
87
|
+
count
|
|
88
|
+
srcText
|
|
89
|
+
srcLocale
|
|
90
|
+
translationLocale
|
|
91
|
+
}
|
|
92
|
+
duplicateSearch
|
|
93
|
+
actionUid
|
|
94
|
+
offlineReportUid
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
const BULK_EXPORT_TM_STRINGS_QUERY = `
|
|
100
|
+
mutation bulkExportTmStrings($bulkExportTmStrings: BulkExportTmStrings!) {
|
|
101
|
+
bulkExportTmStrings(bulkExportTmStrings: $bulkExportTmStrings) {
|
|
102
|
+
actionUid
|
|
103
|
+
totalCount
|
|
104
|
+
processedCount
|
|
105
|
+
errorCount
|
|
106
|
+
executionComplete
|
|
107
|
+
actionStatus
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
`;
|
|
111
|
+
|
|
112
|
+
const BULK_EXPORT_TM_STRINGS_STATUS_QUERY = `
|
|
113
|
+
query bulkExportTmStringsStatus($actionUid: ID!) {
|
|
114
|
+
bulkExportTmStringsStatus(actionUid: $actionUid) {
|
|
115
|
+
actionUid
|
|
116
|
+
totalCount
|
|
117
|
+
processedCount
|
|
118
|
+
errorCount
|
|
119
|
+
executionComplete
|
|
120
|
+
tmxDownloadKey
|
|
121
|
+
expired
|
|
122
|
+
actionStatus
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
export class SmartlingTranslationMemoryApi extends SmartlingBaseFileApi {
|
|
128
|
+
constructor(smartlingApiBaseUrl: string, authApi: AccessTokenProvider, logger: Logger) {
|
|
129
|
+
super(logger);
|
|
130
|
+
this.authApi = authApi;
|
|
131
|
+
this.entrypoint = smartlingApiBaseUrl;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* eslint-disable-next-line class-methods-use-this */
|
|
135
|
+
alterRequestData(uri: string, opts: Record<string, unknown>): Record<string, unknown> {
|
|
136
|
+
// Guard against re-converting an already-built FormData body: makeRequest() calls
|
|
137
|
+
// alterRequestData() again on a 401 retry, reusing the same opts object.
|
|
138
|
+
if (!(opts.body instanceof FormData)
|
|
139
|
+
&& uri.match(/tm-tmx-api\/v2\/accounts\/.*\/tmx\/file$/g)) {
|
|
140
|
+
const formData = new FormData();
|
|
141
|
+
|
|
142
|
+
Object.keys(opts.body).forEach((key) => {
|
|
143
|
+
if (key === "file" && Buffer.isBuffer(opts.body[key])) {
|
|
144
|
+
formData.append(key, opts.body[key], {
|
|
145
|
+
filename: (opts.body as Record<string, string>).fileUri
|
|
146
|
+
});
|
|
147
|
+
} else {
|
|
148
|
+
formData.append(key, opts.body[key]);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
opts.headers["Content-Type"] = formData.getHeaders()["content-type"];
|
|
153
|
+
opts.body = formData;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return opts;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// A 401-triggered retry is not guaranteed byte-safe for a streamed upload
|
|
160
|
+
// (setFileFromLocalFilePath/setFileContent): the underlying Node stream is a one-shot
|
|
161
|
+
// resource, so if it was already partially or fully read by the first attempt, the retried
|
|
162
|
+
// request can go out empty or truncated. The underlying one-shot-stream problem is shared by
|
|
163
|
+
// every alterRequestData-based upload in this SDK (api/job-batches, api/context), not
|
|
164
|
+
// something specific to this method; use setFileContentFromBuffer for a retry-safe upload
|
|
165
|
+
// here (a Buffer can be re-read, and this file's alterRequestData guards against reusing an
|
|
166
|
+
// already-built FormData on retry). job-batches/context lack that FormData guard, so a
|
|
167
|
+
// buffer alone would not make their uploads retry-safe too.
|
|
168
|
+
async importTmxFile(
|
|
169
|
+
accountUid: string, params: ImportTmxFileParameters
|
|
170
|
+
): Promise<TmxImportSummaryDto> {
|
|
171
|
+
const result: TmxImportSummaryDto = await this.makeRequest(
|
|
172
|
+
"post",
|
|
173
|
+
`${this.entrypoint}/tm-tmx-api/v2/accounts/${accountUid}/tmx/file`,
|
|
174
|
+
params.export()
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
if (result.translationMemoryImportErrors?.length || result.parsingErrors?.length) {
|
|
178
|
+
this.logger.warn(`importTmxFile completed with partial errors: ${JSON.stringify({
|
|
179
|
+
translationMemoryImportErrors: result.translationMemoryImportErrors,
|
|
180
|
+
parsingErrors: result.parsingErrors
|
|
181
|
+
})}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async downloadTmxFile(accountUid: string, tmxFileKey: string): Promise<TranslatedFileDto> {
|
|
188
|
+
const encodedTmxFileKey = encodeURIComponent(tmxFileKey);
|
|
189
|
+
|
|
190
|
+
return await SmartlingBaseFileApi.downloadResponseToTranslatedFileDto(
|
|
191
|
+
await this.makeRequest(
|
|
192
|
+
"get",
|
|
193
|
+
`${this.entrypoint}/tm-tmx-api/v2/accounts/${accountUid}/tmx/file/${encodedTmxFileKey}`,
|
|
194
|
+
null,
|
|
195
|
+
ResponseBodyType.RAW_RESPONSE
|
|
196
|
+
)
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async createStringSearch(
|
|
201
|
+
accountUid: string, filter: CreateStringSearchFilterParameters
|
|
202
|
+
): Promise<CreateStringSearchResultDto | null> {
|
|
203
|
+
return await this.executeGraphQl(
|
|
204
|
+
accountUid,
|
|
205
|
+
CREATE_STRING_SEARCH_QUERY,
|
|
206
|
+
{ createStringSearchFilter: filter.export() },
|
|
207
|
+
"createStringSearch"
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async bulkExportTmStrings(
|
|
212
|
+
accountUid: string, params: BulkExportTmStringsParameters
|
|
213
|
+
): Promise<AsyncActionResultDto | null> {
|
|
214
|
+
return await this.executeGraphQl(
|
|
215
|
+
accountUid,
|
|
216
|
+
BULK_EXPORT_TM_STRINGS_QUERY,
|
|
217
|
+
{ bulkExportTmStrings: params.export() },
|
|
218
|
+
"bulkExportTmStrings"
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async getBulkExportTmStringsStatus(
|
|
223
|
+
accountUid: string, actionUid: string
|
|
224
|
+
): Promise<StringsExportAsyncActionResultDto | null> {
|
|
225
|
+
return await this.executeGraphQl(
|
|
226
|
+
accountUid,
|
|
227
|
+
BULK_EXPORT_TM_STRINGS_STATUS_QUERY,
|
|
228
|
+
{ actionUid },
|
|
229
|
+
"bulkExportTmStringsStatus"
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async createTm(accountUid: string, params: CreateTmParameters): Promise<TmDto | null> {
|
|
234
|
+
return await this.executeGraphQl(
|
|
235
|
+
accountUid,
|
|
236
|
+
CREATE_TM_QUERY,
|
|
237
|
+
{ createTm: params.export() },
|
|
238
|
+
"createTm"
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async updateTm(accountUid: string, params: UpdateTmParameters): Promise<TmDto | null> {
|
|
243
|
+
return await this.executeGraphQl(
|
|
244
|
+
accountUid,
|
|
245
|
+
UPDATE_TM_QUERY,
|
|
246
|
+
{ updateTm: params.export() },
|
|
247
|
+
"updateTm"
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// deleteTm isn't documented on the public GraphQL reference site, but it exists in the real
|
|
252
|
+
// backend schema (tmm.graphqls) with the same non-internal-only doc comment as
|
|
253
|
+
// createTm/updateTm ("Deletes a translation memory"), so it's included here per
|
|
254
|
+
// source-code-wins reconciliation.
|
|
255
|
+
async deleteTm(accountUid: string, tmUid: string): Promise<TmDto | null> {
|
|
256
|
+
return await this.executeGraphQl(
|
|
257
|
+
accountUid,
|
|
258
|
+
DELETE_TM_QUERY,
|
|
259
|
+
{ deleteTm: { tmUid } },
|
|
260
|
+
"deleteTm"
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// makeRequest()'s own JSON handling assumes the REST envelope shape ({response: {data}}) and
|
|
265
|
+
// unwraps it automatically - a GraphQL response's {data, errors} envelope doesn't match that,
|
|
266
|
+
// so this method requests the raw Response via ResponseBodyType.RAW_RESPONSE and parses the
|
|
267
|
+
// GraphQL envelope itself instead, mirroring makeRequest's own error-handling shape as closely
|
|
268
|
+
// as the different envelope allows.
|
|
269
|
+
private async executeGraphQl<T>(
|
|
270
|
+
accountUid: string,
|
|
271
|
+
query: string,
|
|
272
|
+
variables: Record<string, unknown>,
|
|
273
|
+
operationName: string
|
|
274
|
+
): Promise<T | null> {
|
|
275
|
+
const response: Response = await this.makeRequest(
|
|
276
|
+
"post",
|
|
277
|
+
`${this.entrypoint}/tm-graphql-api/v2/accounts/${accountUid}/graphql`,
|
|
278
|
+
JSON.stringify({ query, variables }),
|
|
279
|
+
ResponseBodyType.RAW_RESPONSE
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
const requestId = response.headers.get("x-sl-requestid");
|
|
283
|
+
let textResponse: string;
|
|
284
|
+
let jsonResponse: { data?: Record<string, unknown>; errors?: Array<unknown> };
|
|
285
|
+
|
|
286
|
+
try {
|
|
287
|
+
textResponse = await response.text();
|
|
288
|
+
|
|
289
|
+
// The date reviver only matches these bare key names, not a path - harmless today
|
|
290
|
+
// since no nested field in this domain's DTOs shares them, but worth keeping in mind
|
|
291
|
+
// if a future field reuses "created"/"lastModified" for a non-Date value.
|
|
292
|
+
const parsed = JSON.parse(textResponse, (key, value) => {
|
|
293
|
+
if ((key === "created" || key === "lastModified") && value) {
|
|
294
|
+
return new Date(value);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return value;
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
if (!parsed || typeof parsed !== "object") {
|
|
301
|
+
throw new SmartlingException(
|
|
302
|
+
`GraphQL response for operation "${operationName}" is not a JSON object`,
|
|
303
|
+
{ statusCode: response.status, errorResponse: textResponse, requestId }
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
jsonResponse = parsed;
|
|
308
|
+
} catch (e) {
|
|
309
|
+
if (e instanceof SmartlingException) {
|
|
310
|
+
throw e;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
this.logger.error(`Couldn't parse GraphQL response json: ${e.toString()}`);
|
|
314
|
+
|
|
315
|
+
throw new SmartlingException("Couldn't parse GraphQL response json", {
|
|
316
|
+
statusCode: response.status,
|
|
317
|
+
errorResponse: textResponse,
|
|
318
|
+
requestId
|
|
319
|
+
}, e);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// tmxDownloadKey is a bearer-style download token - redact it everywhere this response
|
|
323
|
+
// gets surfaced (the debug log below, and the error payload further down), not just one
|
|
324
|
+
// of the two.
|
|
325
|
+
const redactTmxDownloadKey = (key: string, value: unknown): unknown => (
|
|
326
|
+
key === "tmxDownloadKey" && value ? "[REDACTED]" : value
|
|
327
|
+
);
|
|
328
|
+
const redactedJsonResponse = JSON.parse(JSON.stringify(jsonResponse, redactTmxDownloadKey));
|
|
329
|
+
|
|
330
|
+
this.logger.debug(
|
|
331
|
+
`Received GraphQL response for operation "${operationName}": ${JSON.stringify(redactedJsonResponse)}`
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
if (jsonResponse.errors && !Array.isArray(jsonResponse.errors)) {
|
|
335
|
+
this.logger.warn(`GraphQL response for operation "${operationName}" has an unexpected "errors" shape: ${JSON.stringify(jsonResponse.errors)}`);
|
|
336
|
+
} else if (Array.isArray(jsonResponse.errors) && jsonResponse.errors.length > 0) {
|
|
337
|
+
const firstMessage = (jsonResponse.errors[0] as { message?: string })?.message;
|
|
338
|
+
const suffix = firstMessage ? `: ${firstMessage}` : "";
|
|
339
|
+
|
|
340
|
+
throw new SmartlingException(
|
|
341
|
+
`GraphQL request for operation "${operationName}" failed${suffix}`,
|
|
342
|
+
{
|
|
343
|
+
errors: jsonResponse.errors,
|
|
344
|
+
// Partial data can still be present alongside errors (a nested field-level
|
|
345
|
+
// resolver error doesn't necessarily mean the mutation's side effect - e.g.
|
|
346
|
+
// a TM actually being created - didn't happen), so surface it for recovery
|
|
347
|
+
// rather than discarding it. Redacted the same as the debug log above.
|
|
348
|
+
data: redactedJsonResponse.data,
|
|
349
|
+
statusCode: response.status,
|
|
350
|
+
requestId
|
|
351
|
+
}
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (!jsonResponse.data || !(operationName in jsonResponse.data)) {
|
|
356
|
+
throw new SmartlingException(
|
|
357
|
+
`GraphQL response for operation "${operationName}" is missing the expected field`,
|
|
358
|
+
{ response: redactedJsonResponse, statusCode: response.status, requestId }
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// The operation's result is itself nullable per the real GraphQL schema (none of this
|
|
363
|
+
// domain's Mutation/Query root fields are declared non-null) - a present-but-null value
|
|
364
|
+
// is a legitimate result, not a malformed response, so it's returned as-is rather than
|
|
365
|
+
// thrown. Only a genuinely absent key (checked above) is treated as malformed.
|
|
366
|
+
return jsonResponse.data[operationName] as T | null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BaseParameters } from "../../parameters/index";
|
|
2
|
+
import { ExtendedExportMetadataType } from "./extended-export-metadata-type";
|
|
3
|
+
|
|
4
|
+
export class BulkExportTmStringsParameters extends BaseParameters {
|
|
5
|
+
setSearchUid(searchUid: string): BulkExportTmStringsParameters {
|
|
6
|
+
this.set("searchUid", searchUid);
|
|
7
|
+
|
|
8
|
+
return this;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
setExtendedMetadata(extendedMetadata: boolean): BulkExportTmStringsParameters {
|
|
12
|
+
this.set("extendedMetadata", extendedMetadata);
|
|
13
|
+
|
|
14
|
+
return this;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
setExtendedMetadataType(
|
|
18
|
+
extendedMetadataType: ExtendedExportMetadataType
|
|
19
|
+
): BulkExportTmStringsParameters {
|
|
20
|
+
this.set("extendedMetadataType", extendedMetadataType);
|
|
21
|
+
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setIncludeAllVariants(includeAllVariants: boolean): BulkExportTmStringsParameters {
|
|
26
|
+
this.set("includeAllVariants", includeAllVariants);
|
|
27
|
+
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
}
|