@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.
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,7 +1,8 @@
1
1
  import Crowdin, { SourceFilesModel } from '@crowdin/crowdin-api-client';
2
- import { ClientConfig, Config, IntegrationLogic } from '../models';
2
+ import { ClientConfig, Config, FileProcessLogic, IntegrationLogic } from '../models';
3
3
  export declare function getRootFolder(config: Config, integration: IntegrationLogic, client: Crowdin, projectId: number): Promise<SourceFilesModel.Directory | undefined>;
4
4
  export declare function getOauthRoute(integration: IntegrationLogic): string;
5
5
  export declare function applyIntegrationModuleDefaults(config: Config, integration: IntegrationLogic): void;
6
+ export declare function applyFileProcessorsModuleDefaults(config: Config, fileModule: FileProcessLogic): void;
6
7
  export declare function constructOauthUrl(config: Config, integration: IntegrationLogic): string;
7
8
  export declare function convertClientConfig(clientConfig: ClientConfig): Config;
@@ -32,7 +32,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
32
32
  });
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.convertClientConfig = exports.constructOauthUrl = exports.applyIntegrationModuleDefaults = exports.getOauthRoute = exports.getRootFolder = void 0;
35
+ exports.convertClientConfig = exports.constructOauthUrl = exports.applyFileProcessorsModuleDefaults = exports.applyIntegrationModuleDefaults = exports.getOauthRoute = exports.getRootFolder = void 0;
36
+ const client_s3_1 = require("@aws-sdk/client-s3");
37
+ const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
36
38
  const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
37
39
  const path_1 = require("path");
38
40
  function getRootFolder(config, integration, client, projectId) {
@@ -273,6 +275,22 @@ function applyIntegrationModuleDefaults(config, integration) {
273
275
  }
274
276
  }
275
277
  exports.applyIntegrationModuleDefaults = applyIntegrationModuleDefaults;
278
+ function applyFileProcessorsModuleDefaults(config, fileModule) {
279
+ var _a, _b;
280
+ const AWS_TMP_BUCKET_NAME = (_a = config.awsConfig) === null || _a === void 0 ? void 0 : _a.tmpBucketName;
281
+ const AWS_REGION = (_b = config.awsConfig) === null || _b === void 0 ? void 0 : _b.region;
282
+ if (AWS_TMP_BUCKET_NAME && AWS_REGION && !fileModule.storeFile) {
283
+ const s3 = new client_s3_1.S3Client({ region: AWS_REGION });
284
+ fileModule.storeFile = (content) => __awaiter(this, void 0, void 0, function* () {
285
+ const fileName = `file-${config.identifier}-${Date.now()}`;
286
+ const command = new client_s3_1.PutObjectCommand({ Bucket: AWS_TMP_BUCKET_NAME, Key: fileName, Body: content });
287
+ yield s3.send(command);
288
+ const getObjectCommand = new client_s3_1.GetObjectCommand({ Bucket: AWS_TMP_BUCKET_NAME, Key: fileName });
289
+ return (0, s3_request_presigner_1.getSignedUrl)(s3, getObjectCommand, { expiresIn: 3600 });
290
+ });
291
+ }
292
+ }
293
+ exports.applyFileProcessorsModuleDefaults = applyFileProcessorsModuleDefaults;
276
294
  function constructOauthUrl(config, integration) {
277
295
  var _a, _b, _c;
278
296
  const oauth = integration.oauthLogin;
@@ -293,11 +311,15 @@ function convertClientConfig(clientConfig) {
293
311
  const clientId = clientConfig.clientId || process.env.CROWDIN_CLIENT_ID;
294
312
  const clientSecret = clientConfig.clientSecret || process.env.CROWDIN_CLIENT_SECRET;
295
313
  const port = clientConfig.port || process.env.PORT || 3000;
314
+ const { region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION, tmpBucketName = process.env.AWS_TMP_BUCKET_NAME, } = clientConfig.awsConfig || {};
296
315
  const sentryDsn = clientConfig.sentryDsn || process.env.SENTRY_DSN;
297
316
  if (!baseUrl || !clientId || !clientSecret) {
298
317
  throw new Error('One of following parameters are not defined [baseUrl, clientId, clientSecret]');
299
318
  }
300
319
  return Object.assign(Object.assign({}, clientConfig), { sentryDsn, baseUrl: baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl, clientId,
301
- clientSecret, port: Number(port), dbFolder: clientConfig.dbFolder || (0, path_1.join)(process.cwd(), 'db'), imagePath: clientConfig.imagePath || (0, path_1.join)(process.cwd(), 'logo.png') });
320
+ clientSecret, awsConfig: {
321
+ tmpBucketName,
322
+ region,
323
+ }, port: Number(port), dbFolder: clientConfig.dbFolder || (0, path_1.join)(process.cwd(), 'db'), imagePath: clientConfig.imagePath || (0, path_1.join)(process.cwd(), 'logo.png') });
302
324
  }
303
325
  exports.convertClientConfig = convertClientConfig;
@@ -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);
@@ -5,6 +5,26 @@
5
5
  <body>
6
6
  <div class="i_w">
7
7
  <div class="top">
8
+ {{#if notice}}
9
+ <crowdin-alert
10
+ id="notice"
11
+ title="{{notice.title}}"
12
+ {{#unless notice.icon}}
13
+ no-icon="true"
14
+ {{/unless}}
15
+ {{#if notice.type}}
16
+ type={{notice.type}}
17
+ {{/if}}
18
+ style="display: none; margin-bottom: 12px;"
19
+ >
20
+ <div class="box-center">
21
+ <p class="m-0">{{{notice.content}}}</p>
22
+ </div>
23
+ {{#if notice.close}}
24
+ <crowdin-button onclick="closeAlert(this, 'notice')" class="dismiss-alert" icon>close</crowdin-button>
25
+ {{/if}}
26
+ </crowdin-alert>
27
+ {{/if}}
8
28
  {{#if checkSubscription}}
9
29
  <crowdin-alert id="subscription-info" no-icon="true" type="warning" style="display: none; margin-bottom: 12px;">
10
30
  <div class="box-center">
@@ -763,21 +783,29 @@
763
783
  getSubscriptionInfo();
764
784
  {{/if}}
765
785
 
786
+ function checkAlert(alert, suffix) {
787
+ const name = suffix ?? '{{name}}';
788
+ const revised = localStorage.getItem(`revised_${name}`) === '1';
789
+ if (!revised) {
790
+ alert.style.display = 'block';
791
+ }
792
+ }
793
+ function closeAlert(el, suffix) {
794
+ const name = suffix ?? '{{name}}';
795
+ const alert = el.closest('crowdin-alert');
796
+ alert.style.display = 'none';
797
+ localStorage.setItem(`revised_${name}`, 1);
798
+ }
799
+
766
800
  {{#if uploadTranslations}}
767
801
  const translationInfo = document.getElementById('translation-info');
768
- function checkAlert(alert) {
769
- const revised = localStorage.getItem('revised_{{name}}') === '1';
770
- if (!revised) {
771
- alert.style.display = 'block';
772
- }
773
- }
774
- function closeAlert(el) {
775
- const alert = el.closest('crowdin-alert');
776
- alert.style.display = 'none';
777
- localStorage.setItem('revised_{{name}}', 1);
778
- }
779
802
  checkAlert(translationInfo);
780
803
  {{/if}}
804
+
805
+ {{#if notice}}
806
+ const notice = document.getElementById('notice');
807
+ checkAlert(notice, 'notice');
808
+ {{/if}}
781
809
  </script>
782
810
 
783
811
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.34.2",
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",
@@ -14,12 +14,14 @@
14
14
  "test": "jest"
15
15
  },
16
16
  "dependencies": {
17
+ "@aws-sdk/client-s3": "^3.423.0",
18
+ "@aws-sdk/s3-request-presigner": "^3.423.0",
17
19
  "@crowdin/crowdin-apps-functions": "0.5.1",
18
20
  "@crowdin/logs-formatter": "^2.0.3",
19
21
  "@godaddy/terminus": "^4.12.1",
20
- "@types/pg": "^8.10.2",
22
+ "@types/pg": "^8.10.3",
21
23
  "amqplib": "^0.10.3",
22
- "crypto-js": "^4.0.0",
24
+ "crypto-js": "^4.1.1",
23
25
  "express": "4.18.2",
24
26
  "express-handlebars": "^5.3.5",
25
27
  "mysql2": "^2.3.3",
@@ -31,40 +33,40 @@
31
33
  "uuid": "^8.3.2"
32
34
  },
33
35
  "devDependencies": {
34
- "@babel/preset-react": "^7.22.5",
36
+ "@babel/preset-react": "^7.22.15",
35
37
  "@emotion/react": "^11.11.1",
36
38
  "@emotion/styled": "^11.11.0",
37
- "@mui/icons-material": "^5.14.7",
38
- "@mui/material": "^5.14.7",
39
- "@rjsf/core": "^5.7.3",
40
- "@rjsf/mui": "^5.7.3",
41
- "@rjsf/utils": "^5.7.3",
42
- "@rjsf/validator-ajv8": "^5.7.3",
39
+ "@mui/icons-material": "^5.14.12",
40
+ "@mui/material": "^5.14.12",
41
+ "@rjsf/core": "^5.13.0",
42
+ "@rjsf/mui": "^5.13.0",
43
+ "@rjsf/utils": "^5.13.0",
44
+ "@rjsf/validator-ajv8": "^5.13.0",
43
45
  "@rollup/plugin-babel": "^6.0.3",
44
46
  "@rollup/plugin-commonjs": "^24.0.1",
45
47
  "@rollup/plugin-json": "^6.0.0",
46
- "@rollup/plugin-node-resolve": "^15.0.1",
48
+ "@rollup/plugin-node-resolve": "^15.2.1",
47
49
  "@rollup/plugin-replace": "^5.0.2",
48
50
  "@rollup/plugin-terser": "^0.4.3",
49
- "@types/amqplib": "^0.10.1",
50
- "@types/crypto-js": "^4.1.1",
51
- "@types/express": "4.17.17",
51
+ "@types/amqplib": "^0.10.2",
52
+ "@types/crypto-js": "^4.1.2",
53
+ "@types/express": "4.17.18",
52
54
  "@types/express-handlebars": "^5.3.1",
53
- "@types/jest": "^29.5.2",
54
- "@types/node": "^12.20.55",
55
- "@types/node-cron": "^3.0.8",
55
+ "@types/jest": "^29.5.5",
56
+ "@types/node": "^16.18.57",
57
+ "@types/node-cron": "^3.0.9",
56
58
  "@types/swagger-jsdoc": "^6.0.1",
57
59
  "@typescript-eslint/eslint-plugin": "^2.3.1",
58
60
  "@typescript-eslint/parser": "^2.3.1",
59
61
  "eslint": "^6.4.0",
60
62
  "eslint-config-prettier": "^6.3.0",
61
63
  "eslint-plugin-prettier": "^3.1.1",
62
- "jest": "^29.5.0",
64
+ "jest": "^29.7.0",
63
65
  "jest-junit": "^15.0.0",
64
66
  "prettier": "^2.8.8",
65
67
  "react": "^18.2.0",
66
68
  "react-dom": "^18.2.0",
67
- "rollup": "^3.20.2",
69
+ "rollup": "^3.29.4",
68
70
  "ts-jest": "^29.1.1",
69
71
  "typescript": "^4.9.5"
70
72
  },