@crowdin/app-project-module 0.35.0 → 0.35.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.
@@ -37,8 +37,7 @@ function handle(baseUrl, folder, config) {
37
37
  file = Buffer.from(body.file.content, 'base64');
38
38
  }
39
39
  else if (body.file.contentUrl) {
40
- const rawContent = yield (0, files_1.getFileContent)(body.file.contentUrl);
41
- file = Buffer.from(rawContent).toString('base64');
40
+ file = yield (0, files_1.getFileContent)(body.file.contentUrl);
42
41
  }
43
42
  let response = {};
44
43
  let error;
@@ -71,7 +70,7 @@ function handleBuildFile(baseUrl, dataFolder, config, req, client, context, proj
71
70
  strings = req.strings;
72
71
  }
73
72
  else {
74
- strings = yield (0, files_1.getFileContent)(req.stringsUrl, true);
73
+ strings = yield (0, files_1.getFileStrings)(req.stringsUrl);
75
74
  }
76
75
  let res;
77
76
  if ((req.file.id || !file) && config.exportStrings) {
@@ -113,9 +112,8 @@ function handleParseFile(baseUrl, dataFolder, config, req, client, context, proj
113
112
  maxSize = maxSize / 2;
114
113
  }
115
114
  if (res.previewFile) {
116
- const previewFileEncoded = Buffer.from(res.previewFile).toString('base64');
117
- if (Buffer.byteLength(previewFileEncoded, 'utf8') < maxSize) {
118
- response.preview = previewFileEncoded;
115
+ if (Buffer.byteLength(res.previewFile) < maxSize) {
116
+ response.preview = res.previewFile.toString('base64');
119
117
  }
120
118
  else {
121
119
  let url;
@@ -141,16 +139,17 @@ function handleParseFile(baseUrl, dataFolder, config, req, client, context, proj
141
139
  });
142
140
  }
143
141
  const stringsNDJson = strings.map((s) => JSON.stringify(s)).join('\n\r');
144
- if (Buffer.byteLength(stringsNDJson, 'utf8') < maxSize) {
142
+ const bufferData = Buffer.from(stringsNDJson, 'utf8');
143
+ if (Buffer.byteLength(bufferData) < maxSize) {
145
144
  response.strings = strings;
146
145
  }
147
146
  else {
148
147
  let url;
149
148
  if (config.storeFile) {
150
- url = yield config.storeFile(stringsNDJson);
149
+ url = yield config.storeFile(bufferData);
151
150
  }
152
151
  else {
153
- const storedFile = yield (0, files_1.storeFile)(stringsNDJson, path_1.default.join(dataFolder, 'custom-file-format'));
152
+ const storedFile = yield (0, files_1.storeFile)(bufferData, path_1.default.join(dataFolder, 'custom-file-format'));
154
153
  url = `${baseUrl}?file=${storedFile}`;
155
154
  }
156
155
  response.stringsUrl = url;
@@ -30,14 +30,14 @@ function handle(baseConfig, config, folderName) {
30
30
  let fileContent;
31
31
  let rawContent;
32
32
  if (body.stringsUrl) {
33
- fileContent = yield (0, files_1.getFileContent)(body.stringsUrl, true);
33
+ fileContent = yield (0, files_1.getFileStrings)(body.stringsUrl);
34
34
  }
35
35
  else if (body.strings) {
36
36
  fileContent = body.strings;
37
37
  }
38
38
  else if (body.file.contentUrl) {
39
39
  rawContent = yield (0, files_1.getFileContent)(body.file.contentUrl);
40
- fileContent = Buffer.from(rawContent).toString('base64');
40
+ fileContent = rawContent;
41
41
  }
42
42
  else if (body.file.content) {
43
43
  rawContent = body.file.content;
@@ -45,18 +45,20 @@ function handle(baseConfig, config, folderName) {
45
45
  }
46
46
  if (body.jobType === models_1.ProcessFileJobType.PRE_IMPORT || body.jobType === models_1.ProcessFileJobType.POST_EXPORT) {
47
47
  body.getRawContent = (encoding) => __awaiter(this, void 0, void 0, function* () {
48
- return Buffer.from(rawContent, 'base64').toString(encoding);
48
+ if (typeof rawContent === 'string') {
49
+ return Buffer.from(rawContent, 'base64').toString(encoding);
50
+ }
51
+ return rawContent;
49
52
  });
50
53
  }
51
54
  const fileProcessResult = yield config.fileProcess(body, fileContent, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id);
52
55
  switch (body.jobType) {
53
56
  case models_1.ProcessFileJobType.PRE_IMPORT:
54
57
  case models_1.ProcessFileJobType.POST_EXPORT:
55
- const { contentFile, base64EncodedContent, fileName, fileType, error: contentFileError, } = fileProcessResult;
58
+ const { contentFile, fileName, fileType, error: contentFileError, } = fileProcessResult;
56
59
  if (contentFile) {
57
- const contentFileEncoded = base64EncodedContent || Buffer.from(contentFile).toString('base64');
58
- if (Buffer.byteLength(contentFileEncoded, 'utf8') < files_1.MAX_BODY_SIZE) {
59
- response.content = contentFileEncoded;
60
+ if (Buffer.byteLength(contentFile) < files_1.MAX_BODY_SIZE) {
61
+ response.content = contentFile.toString('base64');
60
62
  }
61
63
  else {
62
64
  let url;
@@ -83,16 +85,17 @@ function handle(baseConfig, config, folderName) {
83
85
  const { strings, error: stringsFileError } = fileProcessResult;
84
86
  if (strings) {
85
87
  const stringsNDJson = strings.map((s) => JSON.stringify(s)).join('\n\r');
86
- if (Buffer.byteLength(stringsNDJson, 'utf8') < files_1.MAX_BODY_SIZE) {
88
+ const bufferData = Buffer.from(stringsNDJson, 'utf-8');
89
+ if (Buffer.byteLength(bufferData) < files_1.MAX_BODY_SIZE) {
87
90
  response.strings = strings;
88
91
  }
89
92
  else {
90
93
  let url;
91
94
  if (config.storeFile) {
92
- url = yield config.storeFile(stringsNDJson);
95
+ url = yield config.storeFile(bufferData);
93
96
  }
94
97
  else {
95
- const storedFile = yield (0, files_1.storeFile)(stringsNDJson, path_1.default.join(folderPath, folderName));
98
+ const storedFile = yield (0, files_1.storeFile)(bufferData, path_1.default.join(folderPath, folderName));
96
99
  url = `${baseFilesUrl}?file=${storedFile}`;
97
100
  }
98
101
  response.stringsUrl = url;
@@ -37,7 +37,7 @@ function handle(config, integration) {
37
37
  }
38
38
  const crowdinFiles = yield (0, cron_1.skipFoldersFromIntegrationRequest)(config, integration, projectId, Object.assign(Object.assign({}, filesToSync), newFiles), crowdinClient.client);
39
39
  const result = yield integration.updateIntegration(projectId, crowdinClient.client, preparedIntegrationCredentials, crowdinFiles, rootFolder, appSettings);
40
- if (newFiles) {
40
+ if (Object.keys(newFiles).length) {
41
41
  yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(Object.assign(Object.assign({}, filesToSync), newFiles)), syncSettings.integrationId, syncSettings.crowdinId, 'schedule', syncSettings.provider);
42
42
  const currentFileSnapshot = yield (0, file_snapshot_1.getCrowdinSnapshot)(config, integration, crowdinClient.client, projectId, appSettings);
43
43
  yield (0, storage_1.getStorage)().updateFilesSnapshot(JSON.stringify(currentFileSnapshot), syncSettings.integrationId, syncSettings.crowdinId, syncSettings.provider);
@@ -17,7 +17,8 @@ function handle(config, integration) {
17
17
  var _a;
18
18
  const { files, provider } = req.body;
19
19
  yield (0, cron_1.createOrUpdateSyncSettings)(config, req, files, provider);
20
- if ((_a = integration.syncNewElements) === null || _a === void 0 ? void 0 : _a[provider]) {
20
+ const appSettings = req.integrationSettings || {};
21
+ if (((_a = integration.syncNewElements) === null || _a === void 0 ? void 0 : _a[provider]) && appSettings[`new-${provider}-files`]) {
21
22
  yield (0, file_snapshot_1.createOrUpdateFileSnapshot)(config, integration, req, provider);
22
23
  }
23
24
  res.status(204).end();
@@ -571,7 +571,7 @@ export interface FileProcessLogic {
571
571
  /**
572
572
  * Override to store huge responses (by default they will be stored in fs)
573
573
  */
574
- storeFile?: (content: string) => Promise<string>;
574
+ storeFile?: (content: Buffer) => Promise<string>;
575
575
  }
576
576
  export interface CustomFileFormatLogic extends FileProcessLogic {
577
577
  /**
@@ -605,28 +605,29 @@ export interface CustomFileFormatLogic extends FileProcessLogic {
605
605
  /**
606
606
  * Used for initial source file upload, source file update, and translation upload
607
607
  */
608
- parseFile?: (fileContent: string | object, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<ParseFileResponse>;
608
+ parseFile?: (fileContent: Buffer, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<ParseFileResponse>;
609
609
  /**
610
610
  * Used for translation download
611
611
  */
612
- buildFile?: (fileContent: string | object, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, strings: ProcessFileString[], client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
612
+ buildFile?: (fileContent: Buffer, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, strings: ProcessFileString[], client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
613
613
  /**
614
614
  * Used for strings export
615
615
  */
616
616
  exportStrings?: (req: Omit<ProcessFileRequest, 'jobType'>, strings: ProcessFileString[], client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
617
617
  }
618
618
  export type FileImportExportLogic = FilePreImportLogic | FilePostImportLogic | FilePreExportLogic | FilePostExportLogic;
619
+ export type FileImportExportContent = ProcessFileString[] | Buffer | undefined;
619
620
  export interface FilePreImportLogic extends FileProcessLogic {
620
- fileProcess: (req: ProcessFileRequest, content: string, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
621
+ fileProcess: (req: ProcessFileRequest, content: FileImportExportContent, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
621
622
  }
622
623
  export interface FilePostImportLogic extends FileProcessLogic {
623
- fileProcess: (req: ProcessFileRequest, content: string, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<ParseFileResponse>;
624
+ fileProcess: (req: ProcessFileRequest, content: FileImportExportContent, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<ParseFileResponse>;
624
625
  }
625
626
  export interface FilePreExportLogic extends FileProcessLogic {
626
- fileProcess: (req: ProcessFileRequest, content: string, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<ParseFileResponse>;
627
+ fileProcess: (req: ProcessFileRequest, content: FileImportExportContent, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<ParseFileResponse>;
627
628
  }
628
629
  export interface FilePostExportLogic extends FileProcessLogic {
629
- fileProcess: (req: ProcessFileRequest, content: string, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
630
+ fileProcess: (req: ProcessFileRequest, content: FileImportExportContent, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
630
631
  }
631
632
  export interface SignaturePatterns {
632
633
  fileName?: string;
@@ -639,7 +640,7 @@ export interface ProcessFileRequest {
639
640
  targetLanguages: LanguagesModel.Language[];
640
641
  strings: ProcessFileString[];
641
642
  stringsUrl: string;
642
- getRawContent?: (encoding: BufferEncoding) => Promise<string>;
643
+ getRawContent?: (encoding: BufferEncoding) => Promise<string | Buffer>;
643
644
  }
644
645
  export interface ProcessFileRecord {
645
646
  content?: string;
@@ -657,13 +658,12 @@ export declare enum ProcessFileJobType {
657
658
  POST_EXPORT = "post-export-file"
658
659
  }
659
660
  export interface ParseFileResponse {
660
- previewFile?: string;
661
+ previewFile?: Buffer;
661
662
  strings?: ProcessFileString[];
662
663
  error?: string;
663
664
  }
664
665
  export interface BuildFileResponse {
665
- contentFile: string;
666
- base64EncodedContent?: string;
666
+ contentFile: Buffer;
667
667
  error?: string;
668
668
  fileName?: string;
669
669
  fileType?: string;
package/out/util/cron.js CHANGED
@@ -112,7 +112,8 @@ function filesCron(config, integration, period) {
112
112
  }
113
113
  const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient, projectId);
114
114
  const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
115
- if ((_a = integration.syncNewElements) === null || _a === void 0 ? void 0 : _a[syncSettings.provider]) {
115
+ if (((_a = integration.syncNewElements) === null || _a === void 0 ? void 0 : _a[syncSettings.provider]) &&
116
+ intConfig[`new-${syncSettings.provider}-files`]) {
116
117
  newFiles = yield (0, file_snapshot_1.getAllNewFiles)({
117
118
  config,
118
119
  integration,
@@ -160,7 +161,7 @@ function filesCron(config, integration, period) {
160
161
  const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
161
162
  yield integration.updateCrowdin(projectId, crowdinClient, apiCredentials, intFiles, rootFolder, intConfig);
162
163
  const newSyncSettingsFiels = allIntFiles.map((file) => (Object.assign(Object.assign({}, file), { schedule: true, sync: false })));
163
- if (newFiles) {
164
+ if (Object.keys(newFiles).length) {
164
165
  yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(newSyncSettingsFiels), syncSettings.integrationId, syncSettings.crowdinId, 'schedule', syncSettings.provider);
165
166
  const currentFileSnapshot = yield (0, file_snapshot_1.getIntegrationSnapshot)(integration, apiCredentials, intConfig);
166
167
  yield (0, storage_1.getStorage)().updateFilesSnapshot(JSON.stringify(currentFileSnapshot), syncSettings.integrationId, syncSettings.crowdinId, syncSettings.provider);
@@ -1,3 +1,6 @@
1
+ /// <reference types="node" />
2
+ import { ProcessFileString } from '../models';
1
3
  export declare const MAX_BODY_SIZE: number;
2
- export declare function storeFile(fileContent: string, folder: string): Promise<string>;
3
- export declare function getFileContent(url: string, isString?: boolean): Promise<any>;
4
+ export declare function storeFile(fileContent: Buffer, folder: string): Promise<string>;
5
+ export declare function getFileContent(url: string): Promise<Buffer>;
6
+ export declare function getFileStrings(url: string): Promise<ProcessFileString[]>;
package/out/util/files.js CHANGED
@@ -12,10 +12,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.getFileContent = exports.storeFile = exports.MAX_BODY_SIZE = void 0;
15
+ exports.getFileStrings = exports.getFileContent = exports.storeFile = exports.MAX_BODY_SIZE = void 0;
16
+ const axios_1 = __importDefault(require("axios"));
16
17
  const fs_1 = __importDefault(require("fs"));
17
18
  const path_1 = __importDefault(require("path"));
18
- const axios_1 = __importDefault(require("axios"));
19
19
  exports.MAX_BODY_SIZE = 4.9 * 1024 * 1024; //4.9mb
20
20
  function storeFile(fileContent, folder) {
21
21
  const fileName = `file${Date.now()}`;
@@ -29,15 +29,19 @@ function storeFile(fileContent, folder) {
29
29
  }));
30
30
  }
31
31
  exports.storeFile = storeFile;
32
- function getFileContent(url, isString = false) {
32
+ function getFileContent(url) {
33
33
  return __awaiter(this, void 0, void 0, function* () {
34
- const response = (yield axios_1.default.get(url)).data;
35
- if (isString) {
36
- // the response is presented in the ndjson format
37
- const jsonRows = response.split(/\n|\n\r/).filter(Boolean);
38
- return jsonRows.map((jsonStringRow) => JSON.parse(jsonStringRow));
39
- }
34
+ const response = (yield axios_1.default.get(url, { responseType: 'arraybuffer' })).data;
40
35
  return response;
41
36
  });
42
37
  }
43
38
  exports.getFileContent = getFileContent;
39
+ function getFileStrings(url) {
40
+ return __awaiter(this, void 0, void 0, function* () {
41
+ const response = (yield axios_1.default.get(url)).data;
42
+ // the response is presented in the ndjson format
43
+ const jsonRows = response.split(/\n|\n\r/).filter(Boolean);
44
+ return jsonRows.map((jsonStringRow) => JSON.parse(jsonStringRow));
45
+ });
46
+ }
47
+ exports.getFileStrings = getFileStrings;
@@ -245,7 +245,7 @@ function prepareWebhookData(config, integration, webhookUrlParam, provider) {
245
245
  if (isWebhookSync) {
246
246
  syncSettings = (yield (0, storage_1.getStorage)().getSyncSettings(clientId, crowdinId, 'schedule', provider));
247
247
  rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient.client, projectId);
248
- if ((_a = integration.syncNewElements) === null || _a === void 0 ? void 0 : _a[provider]) {
248
+ if (((_a = integration.syncNewElements) === null || _a === void 0 ? void 0 : _a[provider]) && appSettings[`new-${provider}-files`]) {
249
249
  newFiles = yield (0, file_snapshot_1.getAllNewFiles)({
250
250
  config,
251
251
  integration,
@@ -289,7 +289,7 @@ function updateCrowdinFromWebhookRequest(args) {
289
289
  node_type: file.nodeType || file.node_type || '1' }, (file.type ? { type: file.type } : {}))));
290
290
  const intFiles = allIntFiles.filter((file) => file.nodeType === '1');
291
291
  const newSyncSettingsFiels = [...syncFiles, ...newFiles].map((file) => (Object.assign(Object.assign({}, file), { schedule: true, sync: false })));
292
- if (newFiles) {
292
+ if (Object.keys(newFiles).length) {
293
293
  yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(newSyncSettingsFiels), syncSettings.integrationId, syncSettings.crowdinId, 'schedule', syncSettings.provider);
294
294
  const currentFileSnapshot = yield (0, file_snapshot_1.getIntegrationSnapshot)(integration, preparedIntegrationCredentials, appSettings);
295
295
  yield (0, storage_1.getStorage)().updateFilesSnapshot(JSON.stringify(currentFileSnapshot), syncSettings.integrationId, syncSettings.crowdinId, syncSettings.provider);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.35.0",
3
+ "version": "0.35.1",
4
4
  "description": "Module that generates for you all common endpoints for serving standalone Crowdin App",
5
5
  "main": "out/index.js",
6
6
  "types": "out/index.d.ts",