@crowdin/app-project-module 0.34.2 → 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);
@@ -65,6 +65,7 @@ function handle(config, integration) {
65
65
  appIdentifier: config.identifier,
66
66
  }
67
67
  : null;
68
+ options.notice = integration.notice;
68
69
  logger(`Routing user to ${view} view`);
69
70
  return res.render(view, options);
70
71
  }));
@@ -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();
package/out/index.js CHANGED
@@ -186,22 +186,27 @@ function addCrowdinEndpoints(app, clientConfig) {
186
186
  }
187
187
  }
188
188
  if (config.customFileFormat) {
189
+ (0, defaults_1.applyFileProcessorsModuleDefaults)(config, config.customFileFormat);
189
190
  app.post('/process', (0, crowdin_client_1.default)(config), (0, custom_file_format_1.default)(config.baseUrl, config.customFileFormat.filesFolder || config.dbFolder, config.customFileFormat));
190
191
  app.get('/file/download', (0, file_download_1.default)(config, config.customFileFormat, 'custom-file-format'));
191
192
  }
192
193
  if (config.filePreImport) {
194
+ (0, defaults_1.applyFileProcessorsModuleDefaults)(config, config.filePreImport);
193
195
  app.post('/pre-import', (0, crowdin_client_1.default)(config), (0, pre_post_process_1.default)(config, config.filePreImport, models_1.ProcessFileJobType.PRE_IMPORT));
194
196
  app.get(`/file/download/${models_1.ProcessFileJobType.PRE_IMPORT}`, (0, file_download_1.default)(config, config.filePreImport, models_1.ProcessFileJobType.PRE_IMPORT));
195
197
  }
196
198
  if (config.filePostImport) {
199
+ (0, defaults_1.applyFileProcessorsModuleDefaults)(config, config.filePostImport);
197
200
  app.post('/post-import', (0, crowdin_client_1.default)(config), (0, pre_post_process_1.default)(config, config.filePostImport, models_1.ProcessFileJobType.POST_IMPORT));
198
201
  app.get(`/file/download/${models_1.ProcessFileJobType.POST_IMPORT}`, (0, file_download_1.default)(config, config.filePostImport, models_1.ProcessFileJobType.POST_IMPORT));
199
202
  }
200
203
  if (config.filePreExport) {
204
+ (0, defaults_1.applyFileProcessorsModuleDefaults)(config, config.filePreExport);
201
205
  app.post('/pre-export', (0, crowdin_client_1.default)(config), (0, pre_post_process_1.default)(config, config.filePreExport, models_1.ProcessFileJobType.PRE_EXPORT));
202
206
  app.get(`/file/download/${models_1.ProcessFileJobType.PRE_EXPORT}`, (0, file_download_1.default)(config, config.filePreExport, models_1.ProcessFileJobType.PRE_EXPORT));
203
207
  }
204
208
  if (config.filePostExport) {
209
+ (0, defaults_1.applyFileProcessorsModuleDefaults)(config, config.filePostExport);
205
210
  app.post('/post-export', (0, crowdin_client_1.default)(config), (0, pre_post_process_1.default)(config, config.filePostExport, models_1.ProcessFileJobType.POST_EXPORT));
206
211
  app.get(`/file/download/${models_1.ProcessFileJobType.POST_EXPORT}`, (0, file_download_1.default)(config, config.filePostExport, models_1.ProcessFileJobType.POST_EXPORT));
207
212
  }
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import Crowdin, { LanguagesModel, SourceFilesModel, SourceStringsModel, TranslationStatusModel } from '@crowdin/crowdin-api-client';
2
3
  import { JwtPayload, VerifyOptions } from '@crowdin/crowdin-apps-functions';
3
4
  import { Request } from 'express';
@@ -156,6 +157,12 @@ export interface ClientConfig extends ImagePath {
156
157
  * Disable formatting logs
157
158
  */
158
159
  disableLogsFormatter?: boolean;
160
+ /**
161
+ * AWS configuration for uploading big files to temporary bucket. Used with customFileFormat and file processors modules.
162
+ *
163
+ * Not necessary to configure if environment variables AWS_REGION and AWS_TMP_BUCKET_NAME are properly set.
164
+ */
165
+ awsConfig?: AWSConfig;
159
166
  }
160
167
  export type Config = ClientConfig & {
161
168
  baseUrl: string;
@@ -296,6 +303,16 @@ export interface IntegrationLogic {
296
303
  * Register Crowdin webhook to get notified when translations are ready
297
304
  */
298
305
  webhooks?: Webhooks;
306
+ /**
307
+ * define a notification for your application at the top of the screen
308
+ */
309
+ notice?: {
310
+ title: string;
311
+ content: string;
312
+ type: NoticeType;
313
+ icon: boolean;
314
+ close: boolean;
315
+ };
299
316
  }
300
317
  export type FormEntity = FormField | FormDelimiter;
301
318
  export interface FormDelimiter {
@@ -554,7 +571,7 @@ export interface FileProcessLogic {
554
571
  /**
555
572
  * Override to store huge responses (by default they will be stored in fs)
556
573
  */
557
- storeFile?: (content: string) => Promise<string>;
574
+ storeFile?: (content: Buffer) => Promise<string>;
558
575
  }
559
576
  export interface CustomFileFormatLogic extends FileProcessLogic {
560
577
  /**
@@ -588,28 +605,29 @@ export interface CustomFileFormatLogic extends FileProcessLogic {
588
605
  /**
589
606
  * Used for initial source file upload, source file update, and translation upload
590
607
  */
591
- 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>;
592
609
  /**
593
610
  * Used for translation download
594
611
  */
595
- 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>;
596
613
  /**
597
614
  * Used for strings export
598
615
  */
599
616
  exportStrings?: (req: Omit<ProcessFileRequest, 'jobType'>, strings: ProcessFileString[], client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
600
617
  }
601
618
  export type FileImportExportLogic = FilePreImportLogic | FilePostImportLogic | FilePreExportLogic | FilePostExportLogic;
619
+ export type FileImportExportContent = ProcessFileString[] | Buffer | undefined;
602
620
  export interface FilePreImportLogic extends FileProcessLogic {
603
- 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>;
604
622
  }
605
623
  export interface FilePostImportLogic extends FileProcessLogic {
606
- 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>;
607
625
  }
608
626
  export interface FilePreExportLogic extends FileProcessLogic {
609
- 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>;
610
628
  }
611
629
  export interface FilePostExportLogic extends FileProcessLogic {
612
- 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>;
613
631
  }
614
632
  export interface SignaturePatterns {
615
633
  fileName?: string;
@@ -622,7 +640,7 @@ export interface ProcessFileRequest {
622
640
  targetLanguages: LanguagesModel.Language[];
623
641
  strings: ProcessFileString[];
624
642
  stringsUrl: string;
625
- getRawContent?: (encoding: string) => Promise<string>;
643
+ getRawContent?: (encoding: BufferEncoding) => Promise<string | Buffer>;
626
644
  }
627
645
  export interface ProcessFileRecord {
628
646
  content?: string;
@@ -640,13 +658,12 @@ export declare enum ProcessFileJobType {
640
658
  POST_EXPORT = "post-export-file"
641
659
  }
642
660
  export interface ParseFileResponse {
643
- previewFile?: string;
661
+ previewFile?: Buffer;
644
662
  strings?: ProcessFileString[];
645
663
  error?: string;
646
664
  }
647
665
  export interface BuildFileResponse {
648
- contentFile: string;
649
- base64EncodedContent?: string;
666
+ contentFile: Buffer;
650
667
  error?: string;
651
668
  fileName?: string;
652
669
  fileType?: string;
@@ -909,4 +926,15 @@ export interface DefaultPermissions {
909
926
  user?: UserPermissions;
910
927
  project?: ProjectPermissions;
911
928
  }
929
+ type NoticeType = 'info' | 'warning' | 'danger' | 'success' | 'error' | 'dataLostWarning';
930
+ export interface AWSConfig {
931
+ /**
932
+ * AWS bucket name for temporary files
933
+ */
934
+ tmpBucketName?: string;
935
+ /**
936
+ * AWS region
937
+ */
938
+ region?: string;
939
+ }
912
940
  export {};