@crowdin/app-project-module 0.39.1 → 0.40.0

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.
Files changed (43) hide show
  1. package/out/handlers/integration/crowdin-update.js +36 -17
  2. package/out/handlers/integration/integration-data.js +2 -0
  3. package/out/handlers/integration/integration-update.js +35 -17
  4. package/out/handlers/integration/integration-webhook.js +1 -1
  5. package/out/handlers/integration/job-cancel.d.ts +3 -0
  6. package/out/handlers/integration/job-cancel.js +28 -0
  7. package/out/handlers/integration/job-info.d.ts +3 -0
  8. package/out/handlers/integration/job-info.js +54 -0
  9. package/out/handlers/integration/main.js +6 -3
  10. package/out/handlers/integration/user-errors.d.ts +3 -0
  11. package/out/handlers/{user-errors.js → integration/user-errors.js} +2 -2
  12. package/out/index.d.ts +2 -1
  13. package/out/index.js +35 -27
  14. package/out/middlewares/crowdin-client.js +1 -0
  15. package/out/middlewares/ui-module.js +1 -0
  16. package/out/models/index.d.ts +48 -17
  17. package/out/models/index.js +1 -0
  18. package/out/models/job.d.ts +44 -0
  19. package/out/models/job.js +16 -0
  20. package/out/static/js/form.js +6 -6
  21. package/out/static/js/main.js +1 -1
  22. package/out/storage/index.d.ts +6 -0
  23. package/out/storage/index.js +3 -0
  24. package/out/storage/mysql.d.ts +6 -0
  25. package/out/storage/mysql.js +106 -0
  26. package/out/storage/postgre.d.ts +6 -0
  27. package/out/storage/postgre.js +107 -0
  28. package/out/storage/sqlite.d.ts +6 -0
  29. package/out/storage/sqlite.js +96 -0
  30. package/out/util/cron.d.ts +1 -0
  31. package/out/util/cron.js +47 -3
  32. package/out/util/defaults.js +4 -11
  33. package/out/util/file-snapshot.js +2 -0
  34. package/out/util/files.d.ts +2 -1
  35. package/out/util/files.js +19 -1
  36. package/out/util/index.js +3 -1
  37. package/out/util/job.d.ts +12 -0
  38. package/out/util/job.js +88 -0
  39. package/out/util/logger.js +4 -0
  40. package/out/util/webhooks.js +50 -4
  41. package/out/views/main.handlebars +153 -5
  42. package/package.json +13 -12
  43. package/out/handlers/user-errors.d.ts +0 -3
@@ -9,9 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ const job_1 = require("../../models/job");
12
13
  const util_1 = require("../../util");
13
14
  const defaults_1 = require("../../util/defaults");
14
15
  const logger_1 = require("../../util/logger");
16
+ const job_2 = require("../../util/job");
15
17
  function handle(config, integration) {
16
18
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
17
19
  var _a, _b;
@@ -26,23 +28,40 @@ function handle(config, integration) {
26
28
  if (((_b = config.api) === null || _b === void 0 ? void 0 : _b.default) && req.body.files) {
27
29
  req.body = req.body.files;
28
30
  }
29
- let message;
30
- try {
31
- const result = yield integration.updateCrowdin(projectId, req.crowdinApiClient, req.integrationCredentials, req.body, rootFolder, req.integrationSettings, uploadTranslations);
32
- if ((0, util_1.isExtendedResultType)(result)) {
33
- message = result.message;
34
- }
35
- }
36
- catch (e) {
37
- yield (0, logger_1.handleUserError)({
38
- action: 'Sync files to Crowdin',
39
- error: e,
40
- crowdinId: req.crowdinContext.crowdinId,
41
- clientId: req.crowdinContext.clientId,
42
- });
43
- throw e;
44
- }
45
- res.send({ message });
31
+ yield (0, job_2.runAsJob)({
32
+ integrationId: req.crowdinContext.clientId,
33
+ crowdinId: req.crowdinContext.crowdinId,
34
+ type: job_1.JobType.UPDATE_TO_CROWDIN,
35
+ title: 'Sync files to Crowdin',
36
+ payload: req.body,
37
+ res,
38
+ jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
39
+ const result = yield integration.updateCrowdin({
40
+ projectId,
41
+ client: req.crowdinApiClient,
42
+ credentials: req.integrationCredentials,
43
+ request: req.body,
44
+ rootFolder,
45
+ appSettings: req.integrationSettings,
46
+ uploadTranslations,
47
+ job,
48
+ });
49
+ let message;
50
+ if ((0, util_1.isExtendedResultType)(result)) {
51
+ message = result.message;
52
+ }
53
+ return { message };
54
+ }),
55
+ onError: (e) => __awaiter(this, void 0, void 0, function* () {
56
+ yield (0, logger_1.handleUserError)({
57
+ action: 'Sync files to Crowdin',
58
+ error: e,
59
+ crowdinId: req.crowdinContext.crowdinId,
60
+ clientId: req.crowdinContext.clientId,
61
+ });
62
+ throw e;
63
+ }),
64
+ });
46
65
  }));
47
66
  }
48
67
  exports.default = handle;
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const util_1 = require("../../util");
13
13
  const logger_1 = require("../../util/logger");
14
+ const files_1 = require("../../util/files");
14
15
  function handle(integration) {
15
16
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
17
  const { parent_id: parentId, search, page } = req.query;
@@ -28,6 +29,7 @@ function handle(integration) {
28
29
  else {
29
30
  files = result;
30
31
  }
32
+ files = (0, files_1.skipFilesByRegex)(files, integration.skipIntegrationNodes);
31
33
  }
32
34
  catch (e) {
33
35
  yield (0, logger_1.handleUserError)({
@@ -9,8 +9,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ const job_1 = require("../../models/job");
12
13
  const util_1 = require("../../util");
13
14
  const defaults_1 = require("../../util/defaults");
15
+ const job_2 = require("../../util/job");
14
16
  const logger_1 = require("../../util/logger");
15
17
  function handle(config, integration) {
16
18
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
@@ -24,23 +26,39 @@ function handle(config, integration) {
24
26
  if (((_a = config.api) === null || _a === void 0 ? void 0 : _a.default) && req.body.files) {
25
27
  req.body = req.body.files;
26
28
  }
27
- let message;
28
- try {
29
- const result = yield integration.updateIntegration(req.crowdinContext.jwtPayload.context.project_id, req.crowdinApiClient, req.integrationCredentials, req.body, rootFolder, req.integrationSettings);
30
- if ((0, util_1.isExtendedResultType)(result)) {
31
- message = result.message;
32
- }
33
- }
34
- catch (e) {
35
- yield (0, logger_1.handleUserError)({
36
- action: 'Sync files to External Service',
37
- error: e,
38
- crowdinId: req.crowdinContext.crowdinId,
39
- clientId: req.crowdinContext.clientId,
40
- });
41
- throw e;
42
- }
43
- res.send({ message });
29
+ yield (0, job_2.runAsJob)({
30
+ integrationId: req.crowdinContext.clientId,
31
+ crowdinId: req.crowdinContext.crowdinId,
32
+ type: job_1.JobType.UPDATE_TO_INTEGRATION,
33
+ title: 'Sync files to ' + config.name,
34
+ payload: req.body,
35
+ res,
36
+ jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
37
+ const result = yield integration.updateIntegration({
38
+ projectId: req.crowdinContext.jwtPayload.context.project_id,
39
+ client: req.crowdinApiClient,
40
+ credentials: req.integrationCredentials,
41
+ request: req.body,
42
+ rootFolder,
43
+ appSettings: req.integrationSettings,
44
+ job,
45
+ });
46
+ let message;
47
+ if ((0, util_1.isExtendedResultType)(result)) {
48
+ message = result.message;
49
+ }
50
+ return { message };
51
+ }),
52
+ onError: (e) => __awaiter(this, void 0, void 0, function* () {
53
+ yield (0, logger_1.handleUserError)({
54
+ action: 'Sync files to External Service',
55
+ error: e,
56
+ crowdinId: req.crowdinContext.crowdinId,
57
+ clientId: req.crowdinContext.clientId,
58
+ });
59
+ throw e;
60
+ }),
61
+ });
44
62
  }));
45
63
  }
46
64
  exports.default = handle;
@@ -25,7 +25,7 @@ function handle(config, integration) {
25
25
  if (!webhookData.syncSettings) {
26
26
  return res.status(200).send({ message: 'Sync is not configured' });
27
27
  }
28
- yield (0, webhooks_1.updateCrowdinFromWebhookRequest)({ integration, webhookData, req });
28
+ yield (0, webhooks_1.updateCrowdinFromWebhookRequest)({ integration, webhookData, req: [req] });
29
29
  res.send({});
30
30
  }
31
31
  else {
@@ -0,0 +1,3 @@
1
+ /// <reference types="qs" />
2
+ import { Response } from 'express';
3
+ export default function handle(): (req: import("../../models").CrowdinClientRequest | import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const job_1 = require("../../models/job");
13
+ const util_1 = require("../../util");
14
+ const storage_1 = require("../../storage");
15
+ function handle() {
16
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
17
+ const id = req.query.job_id || req.body.job_id;
18
+ if (!id) {
19
+ req.logInfo('Job id is absent');
20
+ res.status(400).send('Job id is required');
21
+ return;
22
+ }
23
+ req.logInfo(`User has been canceled the job id: ${id}`);
24
+ yield (0, storage_1.getStorage)().updateJob({ id, status: job_1.JobStatus.CANCELED });
25
+ res.sendStatus(204);
26
+ }));
27
+ }
28
+ exports.default = handle;
@@ -0,0 +1,3 @@
1
+ /// <reference types="qs" />
2
+ import { Response } from 'express';
3
+ export default function handle(): (req: import("../../models").CrowdinClientRequest | import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const job_1 = require("../../models/job");
13
+ const util_1 = require("../../util");
14
+ const storage_1 = require("../../storage");
15
+ function getHumanETA(ms) {
16
+ const seconds = Math.floor(ms / 1000);
17
+ let minutes = Math.floor(seconds / 60);
18
+ const hours = Math.floor(minutes / 60);
19
+ if (seconds < 60) {
20
+ return 'Less than a minute remaining';
21
+ }
22
+ minutes = minutes % 60;
23
+ const timeParts = [];
24
+ if (hours) {
25
+ timeParts.push(`${hours} ${hours > 1 ? 'hours' : 'hour'}`);
26
+ }
27
+ if (minutes) {
28
+ timeParts.push(`${minutes} ${minutes > 1 ? 'minutes' : 'minute'}`);
29
+ }
30
+ return `About ${timeParts.join(' and ')} remaining`;
31
+ }
32
+ function handle() {
33
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
34
+ const id = req.query.job_id || req.body.job_id;
35
+ if (!id) {
36
+ req.logInfo('Get active jobs');
37
+ const jobs = yield (0, storage_1.getStorage)().getActiveJobs({
38
+ integrationId: req.crowdinContext.clientId,
39
+ crowdinId: req.crowdinContext.crowdinId,
40
+ });
41
+ res.send(jobs);
42
+ return;
43
+ }
44
+ req.logInfo(`Get job info for id ${id}`);
45
+ const job = yield (0, storage_1.getStorage)().getJob({ id });
46
+ if (job && job.status === job_1.JobStatus.IN_PROGRESS && job.progress > 5 && job.updatedAt) {
47
+ job.eta = ((Date.now() - job.createdAt) / job.progress) * (100 - job.progress);
48
+ job.info = getHumanETA(job.eta) + (job.info ? `\n${job.info}` : '');
49
+ }
50
+ req.logInfo(`Returning job info ${JSON.stringify(job, null, 2)}`);
51
+ res.send(job);
52
+ }));
53
+ }
54
+ exports.default = handle;
@@ -15,7 +15,7 @@ const defaults_1 = require("../../util/defaults");
15
15
  const logger_1 = require("../../util/logger");
16
16
  function handle(config, integration) {
17
17
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
18
- var _a;
18
+ var _a, _b;
19
19
  const logger = req.logInfo || logger_1.log;
20
20
  const installed = !!req.crowdinApiClient;
21
21
  const loggedIn = !!req.integrationCredentials;
@@ -59,13 +59,16 @@ function handle(config, integration) {
59
59
  options.integrationSearchListener = integration.integrationSearchListener;
60
60
  options.checkSubscription = !(0, connection_1.isAppFree)(config);
61
61
  options.uploadTranslations = integration.uploadTranslations;
62
- options.sentryData = config.sentryDsn
62
+ options.sentryData = process.env.SENTRY_DSN
63
63
  ? {
64
- dsn: config.sentryDsn,
64
+ dsn: process.env.SENTRY_DSN,
65
65
  appIdentifier: config.identifier,
66
66
  }
67
67
  : null;
68
68
  options.notice = integration.notice;
69
+ options.asyncProgress = {
70
+ checkInterval: ((_b = integration.asyncProgress) === null || _b === void 0 ? void 0 : _b.checkInterval) || 1000,
71
+ };
69
72
  logger(`Routing user to ${view} view`);
70
73
  return res.render(view, options);
71
74
  }));
@@ -0,0 +1,3 @@
1
+ /// <reference types="qs" />
2
+ import { Response } from 'express';
3
+ export default function handle(): (req: import("../../models").CrowdinClientRequest | import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- const storage_1 = require("../storage");
13
- const util_1 = require("../util");
12
+ const storage_1 = require("../../storage");
13
+ const util_1 = require("../../util");
14
14
  function handle() {
15
15
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
16
  var _a;
package/out/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { Express } from 'express';
2
- import { ClientConfig, Config, CrowdinAppUtilities } from './models';
2
+ import { ClientConfig, Config, CrowdinAppUtilities, CrowdinMetadataStore } from './models';
3
3
  import express from './util/terminus-express';
4
4
  export { ProjectPermissions, Scope, UserPermissions } from './models';
5
5
  export { express };
6
+ export declare const metadataStore: CrowdinMetadataStore;
6
7
  export declare function addCrowdinEndpoints(app: Express, clientConfig: Config | ClientConfig): CrowdinAppUtilities;
7
8
  export declare function createApp(clientConfig: ClientConfig): void;
package/out/index.js CHANGED
@@ -35,11 +35,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.createApp = exports.addCrowdinEndpoints = exports.express = exports.UserPermissions = exports.Scope = exports.ProjectPermissions = void 0;
38
+ exports.createApp = exports.addCrowdinEndpoints = exports.metadataStore = exports.express = exports.UserPermissions = exports.Scope = exports.ProjectPermissions = void 0;
39
+ const logsFormatter = __importStar(require("@crowdin/logs-formatter"));
39
40
  const express_handlebars_1 = __importDefault(require("express-handlebars"));
40
41
  const cron = __importStar(require("node-cron"));
41
42
  const path_1 = require("path");
42
- const logsFormatter = __importStar(require("@crowdin/logs-formatter"));
43
43
  const translate_1 = __importDefault(require("./handlers/custom-mt/translate"));
44
44
  const custom_file_format_1 = __importDefault(require("./handlers/file-processing/custom-file-format"));
45
45
  const file_download_1 = __importDefault(require("./handlers/file-processing/file-download"));
@@ -62,12 +62,14 @@ const oauth_login_1 = __importDefault(require("./handlers/integration/oauth-logi
62
62
  const oauth_url_1 = __importDefault(require("./handlers/integration/oauth-url"));
63
63
  const settings_save_1 = __importDefault(require("./handlers/integration/settings-save"));
64
64
  const subscription_info_1 = __importDefault(require("./handlers/integration/subscription-info"));
65
+ const job_info_1 = __importDefault(require("./handlers/integration/job-info"));
66
+ const job_cancel_1 = __importDefault(require("./handlers/integration/job-cancel"));
65
67
  const sync_settings_1 = __importDefault(require("./handlers/integration/sync-settings"));
66
68
  const sync_settings_save_1 = __importDefault(require("./handlers/integration/sync-settings-save"));
69
+ const user_errors_1 = __importDefault(require("./handlers/integration/user-errors"));
67
70
  const manifest_1 = __importDefault(require("./handlers/manifest"));
68
71
  const subscription_paid_1 = __importDefault(require("./handlers/subscription-paid"));
69
72
  const uninstall_1 = __importDefault(require("./handlers/uninstall"));
70
- const user_errors_1 = __importDefault(require("./handlers/user-errors"));
71
73
  const crowdin_client_1 = __importStar(require("./middlewares/crowdin-client"));
72
74
  const integration_credentials_1 = __importDefault(require("./middlewares/integration-credentials"));
73
75
  const json_response_1 = __importDefault(require("./middlewares/json-response"));
@@ -89,6 +91,29 @@ var models_2 = require("./models");
89
91
  Object.defineProperty(exports, "ProjectPermissions", { enumerable: true, get: function () { return models_2.ProjectPermissions; } });
90
92
  Object.defineProperty(exports, "Scope", { enumerable: true, get: function () { return models_2.Scope; } });
91
93
  Object.defineProperty(exports, "UserPermissions", { enumerable: true, get: function () { return models_2.UserPermissions; } });
94
+ exports.metadataStore = {
95
+ getMetadata: (id) => {
96
+ return storage.getStorage().getMetadata(id);
97
+ },
98
+ saveMetadata: (id, metadata, crowdinId) => __awaiter(void 0, void 0, void 0, function* () {
99
+ const existing = yield storage.getStorage().getMetadata(id);
100
+ if (existing) {
101
+ yield storage.getStorage().updateMetadata(id, metadata, crowdinId);
102
+ }
103
+ else {
104
+ yield storage.getStorage().saveMetadata(id, metadata, crowdinId);
105
+ }
106
+ }),
107
+ deleteMetadata: (id) => {
108
+ return storage.getStorage().deleteMetadata(id);
109
+ },
110
+ getUserSettings: (clientId) => __awaiter(void 0, void 0, void 0, function* () {
111
+ const integrationCredentials = yield storage.getStorage().getIntegrationCredentials(clientId);
112
+ if (integrationCredentials === null || integrationCredentials === void 0 ? void 0 : integrationCredentials.config) {
113
+ return JSON.parse(integrationCredentials.config);
114
+ }
115
+ }),
116
+ };
92
117
  function addCrowdinEndpoints(app, clientConfig) {
93
118
  var _a, _b, _c, _d, _e, _f, _g;
94
119
  const config = (0, defaults_1.convertClientConfig)(clientConfig);
@@ -100,6 +125,7 @@ function addCrowdinEndpoints(app, clientConfig) {
100
125
  app.use(terminus_express_1.default.json({ limit: '50mb' }));
101
126
  if (!config.disableLogsFormatter) {
102
127
  logsFormatter.setup();
128
+ app.use(logsFormatter.contextResolverMiddleware());
103
129
  app.use(logsFormatter.expressMiddleware());
104
130
  }
105
131
  app.use('/assets', terminus_express_1.default.static((0, path_1.join)(__dirname, 'static')));
@@ -145,6 +171,8 @@ function addCrowdinEndpoints(app, clientConfig) {
145
171
  app.get((0, util_1.getLogoUrl)(integrationLogic, '/integration'), (req, res) => res.sendFile(integrationLogic.imagePath || config.imagePath));
146
172
  app.get('/', (0, crowdin_client_1.default)(config, true, false), (0, integration_credentials_1.default)(config, integrationLogic, true), (0, main_1.default)(config, integrationLogic));
147
173
  app.get('/api/subscription-info', json_response_1.default, (0, crowdin_client_1.default)(config), (0, subscription_info_1.default)(config));
174
+ app.get('/api/jobs', json_response_1.default, (0, crowdin_client_1.default)(config), (0, job_info_1.default)());
175
+ app.delete('/api/jobs', json_response_1.default, (0, crowdin_client_1.default)(config), (0, job_cancel_1.default)());
148
176
  app.post('/api/settings', (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, integrationLogic), (0, settings_save_1.default)(config, integrationLogic));
149
177
  app.post('/api/login', (0, crowdin_client_1.default)(config, false, false), (0, integration_login_1.default)(config, integrationLogic));
150
178
  app.post('/api/logout', (0, crowdin_client_1.default)(config, false, false), (0, integration_credentials_1.default)(config, integrationLogic), (0, integration_logout_1.default)(config, integrationLogic));
@@ -186,6 +214,7 @@ function addCrowdinEndpoints(app, clientConfig) {
186
214
  }
187
215
  }
188
216
  app.get('/api/user-errors', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, integrationLogic), (0, user_errors_1.default)());
217
+ cron.schedule('0 0 1 * *', () => (0, cron_1.removeFinishedJobs)());
189
218
  }
190
219
  if (config.customFileFormat) {
191
220
  (0, defaults_1.applyFileProcessorsModuleDefaults)(config, config.customFileFormat);
@@ -263,25 +292,7 @@ function addCrowdinEndpoints(app, clientConfig) {
263
292
  app.get('/api/form-data', json_response_1.default, (0, crowdin_client_1.default)(config), (0, form_data_display_1.default)());
264
293
  app.post('/api/form-data', (0, crowdin_client_1.default)(config), (0, form_data_save_1.default)());
265
294
  }
266
- return {
267
- getMetadata: storage.getStorage().getMetadata.bind(storage.getStorage()),
268
- saveMetadata: (id, metadata, crowdinId) => __awaiter(this, void 0, void 0, function* () {
269
- const existing = yield storage.getStorage().getMetadata(id);
270
- if (existing) {
271
- yield storage.getStorage().updateMetadata(id, metadata, crowdinId);
272
- }
273
- else {
274
- yield storage.getStorage().saveMetadata(id, metadata, crowdinId);
275
- }
276
- }),
277
- deleteMetadata: storage.getStorage().deleteMetadata.bind(storage.getStorage()),
278
- getUserSettings: (clientId) => __awaiter(this, void 0, void 0, function* () {
279
- const integrationCredentials = yield storage.getStorage().getIntegrationCredentials(clientId);
280
- if (integrationCredentials === null || integrationCredentials === void 0 ? void 0 : integrationCredentials.config) {
281
- return JSON.parse(integrationCredentials.config);
282
- }
283
- }),
284
- establishCrowdinConnection: (authRequest) => {
295
+ return Object.assign(Object.assign({}, exports.metadataStore), { establishCrowdinConnection: (authRequest) => {
285
296
  let jwtToken = '';
286
297
  if (typeof authRequest === 'string') {
287
298
  jwtToken = authRequest;
@@ -290,9 +301,7 @@ function addCrowdinEndpoints(app, clientConfig) {
290
301
  jwtToken = (0, crowdin_client_1.getToken)(authRequest);
291
302
  }
292
303
  return (0, crowdin_client_1.prepareCrowdinRequest)(jwtToken, config);
293
- },
294
- encryptCrowdinConnection: (data) => (0, util_1.encryptData)(config, JSON.stringify(data)),
295
- dencryptCrowdinConnection: (hash) => __awaiter(this, void 0, void 0, function* () {
304
+ }, encryptCrowdinConnection: (data) => (0, util_1.encryptData)(config, JSON.stringify(data)), dencryptCrowdinConnection: (hash) => __awaiter(this, void 0, void 0, function* () {
296
305
  const { crowdinId, extra } = JSON.parse((0, util_1.decryptData)(config, hash));
297
306
  const credentials = yield storage.getStorage().getCrowdinCredentials(crowdinId);
298
307
  if (!credentials) {
@@ -300,8 +309,7 @@ function addCrowdinEndpoints(app, clientConfig) {
300
309
  }
301
310
  const { client } = yield (0, connection_1.prepareCrowdinClient)({ config, credentials });
302
311
  return { client, extra };
303
- }),
304
- };
312
+ }) });
305
313
  }
306
314
  exports.addCrowdinEndpoints = addCrowdinEndpoints;
307
315
  function createApp(clientConfig) {
@@ -24,6 +24,7 @@ function prepareCrowdinRequest(jwtToken, config, optional = false, checkSubscrip
24
24
  jwtPayload,
25
25
  clientId: (0, crowdin_apps_functions_1.constructCrowdinIdFromJwtPayload)(jwtPayload),
26
26
  crowdinId: `${jwtPayload.domain || jwtPayload.context.organization_id}`,
27
+ appIdentifier: config.identifier,
27
28
  };
28
29
  const logInfo = (0, logger_1.withContext)(context);
29
30
  const logError = (0, logger_1.withContextError)(context);
@@ -31,6 +31,7 @@ function handle(config, allowUnauthorized = false) {
31
31
  jwtPayload,
32
32
  clientId: (0, crowdin_apps_functions_1.constructCrowdinIdFromJwtPayload)(jwtPayload),
33
33
  crowdinId: id,
34
+ appIdentifier: config.identifier,
34
35
  };
35
36
  const logInfo = (0, logger_1.withContext)(context);
36
37
  logInfo('Loading crowdin credentials');
@@ -5,6 +5,7 @@ import { Request } from 'express';
5
5
  import { MySQLStorageConfig } from '../storage/mysql';
6
6
  import { PostgreStorageConfig } from '../storage/postgre';
7
7
  import { LogErrorFunction, LogFunction } from '../util/logger';
8
+ import { JobClient } from './job';
8
9
  export interface ClientConfig extends ImagePath {
9
10
  /**
10
11
  * Authentication Crowdin App type: "authorization_code", "crowdin_app". Default: "crowdin_app"
@@ -153,10 +154,6 @@ export interface ClientConfig extends ImagePath {
153
154
  filePostImport?: FilePostImportLogic;
154
155
  filePreExport?: FilePreExportLogic;
155
156
  filePostExport?: FilePostExportLogic;
156
- /**
157
- * sentry dsn identifier of sentry project
158
- */
159
- sentryDsn?: string;
160
157
  /**
161
158
  * Disable formatting logs
162
159
  */
@@ -201,7 +198,8 @@ export declare enum Scope {
201
198
  SOURCE_FILES_AND_STRINGS = "project.source",
202
199
  WEBHOOKS = "project.webhook",
203
200
  TRANSLATIONS = "project.translation",
204
- SCREENSHOTS = "project.screenshot"
201
+ SCREENSHOTS = "project.screenshot",
202
+ SECURITY_LOGS = "security-log"
205
203
  }
206
204
  export interface IntegrationLogic {
207
205
  /**
@@ -235,11 +233,28 @@ export interface IntegrationLogic {
235
233
  /**
236
234
  * function to update crowdin files (e.g. pull integration data to crowdin source files)
237
235
  */
238
- updateCrowdin: (projectId: number, client: Crowdin, apiCredentials: any, request: IntegrationFile[], appRootFolder?: SourceFilesModel.Directory, config?: any, uploadTranslations?: boolean) => Promise<void | ExtendedResult<void>>;
236
+ updateCrowdin: ({ projectId, client, credentials, request, rootFolder, appSettings, uploadTranslations, job, }: {
237
+ projectId: number;
238
+ client: Crowdin;
239
+ credentials: any;
240
+ request: IntegrationFile[];
241
+ rootFolder?: SourceFilesModel.Directory;
242
+ appSettings?: any;
243
+ uploadTranslations?: boolean;
244
+ job: JobClient;
245
+ }) => Promise<void | ExtendedResult<void>>;
239
246
  /**
240
247
  * function to update integration content (e.g. load crowdin translations and push them to integration service)
241
248
  */
242
- updateIntegration: (projectId: number, client: Crowdin, apiCredentials: any, request: UpdateIntegrationRequest, appRootFolder?: SourceFilesModel.Directory, config?: any) => Promise<void | ExtendedResult<void>>;
249
+ updateIntegration: ({ projectId, client, credentials, request, rootFolder, appSettings, job, }: {
250
+ projectId: number;
251
+ client: Crowdin;
252
+ credentials: any;
253
+ request: UpdateIntegrationRequest;
254
+ rootFolder?: SourceFilesModel.Directory;
255
+ appSettings?: any;
256
+ job: JobClient;
257
+ }) => Promise<void | ExtendedResult<void>>;
243
258
  /**
244
259
  * function to define configuration(settings) modal for you app (by default app will not have any custom settings)
245
260
  */
@@ -317,6 +332,19 @@ export interface IntegrationLogic {
317
332
  icon: boolean;
318
333
  close: boolean;
319
334
  };
335
+ skipIntegrationNodes?: SkipIntegrationNodes;
336
+ /**
337
+ * Async progress checking time interval to update job progress, im ms.
338
+ *
339
+ * Default 1000
340
+ */
341
+ asyncProgress?: {
342
+ checkInterval?: number;
343
+ };
344
+ }
345
+ export interface SkipIntegrationNodes {
346
+ fileNamePattern?: string;
347
+ folderNamePattern?: string;
320
348
  }
321
349
  export type FormEntity = FormField | FormDelimiter;
322
350
  export interface FormDelimiter {
@@ -533,6 +561,7 @@ export interface CrowdinContextInfo {
533
561
  jwtPayload: JwtPayload;
534
562
  crowdinId: string;
535
563
  clientId: string;
564
+ appIdentifier: string;
536
565
  }
537
566
  export declare enum SubscriptionInfoType {
538
567
  TRIAL = "trial",
@@ -814,14 +843,7 @@ export declare enum ContextOptionsTypes {
814
843
  NEW_TAB = "new_tab",
815
844
  REDIRECT = "redirect"
816
845
  }
817
- export interface CrowdinAppUtilities {
818
- saveMetadata: (id: string, metadata: any, crowdinId?: string) => Promise<void>;
819
- getMetadata: (id: string) => Promise<any | undefined>;
820
- deleteMetadata: (id: string) => Promise<void>;
821
- /**
822
- * Settings that users manage in the integration module
823
- */
824
- getUserSettings: (clientId: string) => Promise<any | undefined>;
846
+ export interface CrowdinAppUtilities extends CrowdinMetadataStore {
825
847
  establishCrowdinConnection: (authRequest: string | CrowdinClientRequest) => Promise<{
826
848
  context: CrowdinContextInfo;
827
849
  client?: Crowdin;
@@ -835,6 +857,15 @@ export interface CrowdinAppUtilities {
835
857
  extra: Record<string, any>;
836
858
  }>;
837
859
  }
860
+ export interface CrowdinMetadataStore {
861
+ saveMetadata: (id: string, metadata: any, crowdinId?: string) => Promise<void>;
862
+ getMetadata: (id: string) => Promise<any | undefined>;
863
+ deleteMetadata: (id: string) => Promise<void>;
864
+ /**
865
+ * Settings that users manage in the integration module
866
+ */
867
+ getUserSettings: (clientId: string) => Promise<any | undefined>;
868
+ }
838
869
  export declare enum Provider {
839
870
  CROWDIN = "crowdin",
840
871
  INTEGRATION = "integration"
@@ -914,7 +945,7 @@ export interface Webhooks {
914
945
  crowdinWebhooks?: (client: Crowdin, projectId: number, available: boolean, config?: AppSettings) => Promise<void>;
915
946
  integrationWebhooks?: (apiCredentials: any, urlParam: string, available: boolean, config?: AppSettings, syncSettings?: any) => Promise<void>;
916
947
  crowdinWebhookInterceptor?: (projectId: number, client: Crowdin, appRootFolder?: SourceFilesModel.Directory, config?: any, syncSettings?: any, webhookRequest?: any) => Promise<UpdateIntegrationRequest>;
917
- integrationWebhookInterceptor?: (projectId: number, client: Crowdin, apiCredentials: any, appRootFolder?: SourceFilesModel.Directory, config?: AppSettings, syncSettings?: any, webhookRequest?: any) => Promise<IntegrationFile[]>;
948
+ integrationWebhookInterceptor?: (projectId: number, client: Crowdin, apiCredentials: any, appRootFolder?: SourceFilesModel.Directory, config?: AppSettings, syncSettings?: any, webhookRequests?: any) => Promise<IntegrationFile[]>;
918
949
  queueUrl: string;
919
950
  }
920
951
  export declare enum SyncCondition {
@@ -951,7 +982,7 @@ export interface GetAllNewFilesArgs {
951
982
  export interface UpdateCrowdinWebhookPayloadsArgs {
952
983
  integration: IntegrationLogic;
953
984
  webhookData: any;
954
- req: Request;
985
+ req: Request[];
955
986
  }
956
987
  export interface FilterSyncFilesArgs {
957
988
  projectId: number;
@@ -24,6 +24,7 @@ var Scope;
24
24
  Scope["WEBHOOKS"] = "project.webhook";
25
25
  Scope["TRANSLATIONS"] = "project.translation";
26
26
  Scope["SCREENSHOTS"] = "project.screenshot";
27
+ Scope["SECURITY_LOGS"] = "security-log";
27
28
  })(Scope = exports.Scope || (exports.Scope = {}));
28
29
  var AccountType;
29
30
  (function (AccountType) {