@crowdin/app-project-module 0.30.3 → 0.32.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 (82) hide show
  1. package/out/handlers/custom-mt/translate.d.ts +2 -2
  2. package/out/handlers/custom-mt/translate.js +8 -6
  3. package/out/handlers/file-processing/custom-file-format.d.ts +2 -2
  4. package/out/handlers/file-processing/custom-file-format.js +4 -4
  5. package/out/handlers/file-processing/file-download.d.ts +1 -1
  6. package/out/handlers/file-processing/file-download.js +3 -2
  7. package/out/handlers/file-processing/pre-post-process.d.ts +2 -2
  8. package/out/handlers/file-processing/pre-post-process.js +11 -3
  9. package/out/handlers/form-data-display.d.ts +1 -1
  10. package/out/handlers/form-data-save.d.ts +1 -1
  11. package/out/handlers/install.d.ts +1 -1
  12. package/out/handlers/install.js +5 -3
  13. package/out/handlers/integration/crowdin-file-progress.d.ts +2 -2
  14. package/out/handlers/integration/crowdin-file-progress.js +4 -4
  15. package/out/handlers/integration/crowdin-files.d.ts +1 -1
  16. package/out/handlers/integration/crowdin-files.js +4 -4
  17. package/out/handlers/integration/crowdin-project.d.ts +2 -2
  18. package/out/handlers/integration/crowdin-project.js +4 -4
  19. package/out/handlers/integration/crowdin-update.d.ts +1 -1
  20. package/out/handlers/integration/crowdin-update.js +4 -4
  21. package/out/handlers/integration/crowdin-webhook.d.ts +1 -1
  22. package/out/handlers/integration/crowdin-webhook.js +1 -1
  23. package/out/handlers/integration/integration-data.d.ts +2 -2
  24. package/out/handlers/integration/integration-data.js +4 -4
  25. package/out/handlers/integration/integration-login.d.ts +2 -2
  26. package/out/handlers/integration/integration-login.js +4 -4
  27. package/out/handlers/integration/integration-logout.d.ts +1 -1
  28. package/out/handlers/integration/integration-logout.js +4 -4
  29. package/out/handlers/integration/integration-update.d.ts +1 -1
  30. package/out/handlers/integration/integration-update.js +3 -3
  31. package/out/handlers/integration/integration-webhook.d.ts +1 -1
  32. package/out/handlers/integration/integration-webhook.js +1 -1
  33. package/out/handlers/integration/main.d.ts +1 -1
  34. package/out/handlers/integration/main.js +11 -3
  35. package/out/handlers/integration/oauth-login.d.ts +1 -1
  36. package/out/handlers/integration/oauth-login.js +6 -10
  37. package/out/handlers/integration/oauth-url.d.ts +2 -2
  38. package/out/handlers/integration/oauth-url.js +3 -3
  39. package/out/handlers/integration/settings-save.d.ts +1 -1
  40. package/out/handlers/integration/settings-save.js +2 -2
  41. package/out/handlers/integration/settings.d.ts +1 -2
  42. package/out/handlers/integration/settings.js +2 -2
  43. package/out/handlers/integration/sync-settings-save.d.ts +1 -1
  44. package/out/handlers/integration/sync-settings-save.js +1 -1
  45. package/out/handlers/integration/sync-settings.d.ts +1 -2
  46. package/out/handlers/integration/sync-settings.js +4 -4
  47. package/out/handlers/integration/synced-files.d.ts +1 -2
  48. package/out/handlers/integration/synced-files.js +4 -4
  49. package/out/handlers/manifest.js +9 -18
  50. package/out/handlers/subscription-paid.d.ts +1 -2
  51. package/out/handlers/subscription-paid.js +4 -3
  52. package/out/handlers/uninstall.d.ts +1 -1
  53. package/out/handlers/uninstall.js +7 -6
  54. package/out/index.d.ts +1 -1
  55. package/out/index.js +37 -32
  56. package/out/middlewares/crowdin-client.d.ts +4 -1
  57. package/out/middlewares/crowdin-client.js +26 -16
  58. package/out/middlewares/integration-credentials.d.ts +1 -1
  59. package/out/middlewares/integration-credentials.js +2 -2
  60. package/out/middlewares/render-ui-module.d.ts +2 -2
  61. package/out/middlewares/render-ui-module.js +2 -2
  62. package/out/middlewares/ui-module.d.ts +1 -1
  63. package/out/middlewares/ui-module.js +17 -6
  64. package/out/models/index.d.ts +27 -2
  65. package/out/models/index.js +13 -1
  66. package/out/storage/index.js +4 -4
  67. package/out/util/api/api.js +4 -4
  68. package/out/util/connection.d.ts +11 -2
  69. package/out/util/connection.js +17 -16
  70. package/out/util/cron.js +43 -25
  71. package/out/util/defaults.js +2 -1
  72. package/out/util/file-snapshot.d.ts +1 -1
  73. package/out/util/file-snapshot.js +4 -4
  74. package/out/util/index.d.ts +3 -6
  75. package/out/util/index.js +12 -42
  76. package/out/util/logger.d.ts +14 -0
  77. package/out/util/logger.js +71 -0
  78. package/out/util/synced-files.js +4 -4
  79. package/out/util/webhooks.d.ts +1 -1
  80. package/out/util/webhooks.js +6 -6
  81. package/out/views/partials/head.handlebars +28 -1
  82. package/package.json +1 -1
@@ -15,7 +15,7 @@ const connection_1 = require("../util/connection");
15
15
  function handle(config, integration, optional = false) {
16
16
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
17
17
  const clientId = req.crowdinContext.clientId;
18
- (0, util_1.log)(`Loading integration credentials for client ${clientId}`, config.logger);
18
+ req.logInfo(`Loading integration credentials for client ${clientId}`);
19
19
  const integrationCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(clientId);
20
20
  if (!integrationCredentials) {
21
21
  if (optional) {
@@ -34,6 +34,6 @@ function handle(config, integration, optional = false) {
34
34
  throw new util_1.CodeError('Credentials to integration either exprired or invalid', 401);
35
35
  }
36
36
  next();
37
- }), config.onError);
37
+ }));
38
38
  }
39
39
  exports.default = handle;
@@ -1,4 +1,4 @@
1
1
  /// <reference types="qs" />
2
2
  import express from 'express';
3
- import { Config, UiModule } from '../models';
4
- export default function handle(config: Config, moduleConfig: UiModule): (req: express.Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: express.Response<any, Record<string, any>>, next: Function) => void;
3
+ import { UiModule } from '../models';
4
+ export default function handle(moduleConfig: UiModule): (req: import("../models").CrowdinClientRequest | express.Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: express.Response<any, Record<string, any>>, next: Function) => void;
@@ -14,7 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const express_1 = __importDefault(require("express"));
16
16
  const util_1 = require("../util");
17
- function handle(config, moduleConfig) {
17
+ function handle(moduleConfig) {
18
18
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
19
19
  if (moduleConfig.formSchema) {
20
20
  return res.render('form', {
@@ -28,6 +28,6 @@ function handle(config, moduleConfig) {
28
28
  return express_1.default.static(moduleConfig.uiPath)(req, res, next);
29
29
  }
30
30
  throw new Error('uiPath or formSchema should be provided for module');
31
- }), config.onError);
31
+ }));
32
32
  }
33
33
  exports.default = handle;
@@ -1,4 +1,4 @@
1
1
  /// <reference types="qs" />
2
2
  import { Request, Response } from 'express';
3
3
  import { Config } from '../models';
4
- export default function handle(config: Config, allowUnauthorized?: boolean): (req: Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
4
+ export default function handle(config: Config, allowUnauthorized?: boolean): (req: import("../models").CrowdinClientRequest | Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -13,6 +13,7 @@ const crowdin_apps_functions_1 = require("@crowdin/crowdin-apps-functions");
13
13
  const storage_1 = require("../storage");
14
14
  const util_1 = require("../util");
15
15
  const connection_1 = require("../util/connection");
16
+ const logger_1 = require("../util/logger");
16
17
  function handle(config, allowUnauthorized = false) {
17
18
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
18
19
  if (allowUnauthorized) {
@@ -23,21 +24,31 @@ function handle(config, allowUnauthorized = false) {
23
24
  if (!jwtToken) {
24
25
  return res.status(403).send({ error: 'Access denied' });
25
26
  }
26
- (0, util_1.log)('Validating jwt token from incoming request', config.logger);
27
+ (0, logger_1.log)('Validating jwt token from incoming request');
27
28
  const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(jwtToken, config.clientSecret, config.jwtValidationOptions);
28
29
  const id = `${jwtPayload.domain || jwtPayload.context.organization_id}`;
29
- (0, util_1.log)('Loading crowdin credentials', config.logger);
30
+ const logInfo = (0, logger_1.withContext)({
31
+ orgId: id,
32
+ userId: (0, crowdin_apps_functions_1.constructCrowdinIdFromJwtPayload)(jwtPayload),
33
+ projectId: jwtPayload.context.project_id,
34
+ });
35
+ logInfo('Loading crowdin credentials');
30
36
  const credentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(id);
31
37
  if (!credentials) {
32
38
  throw new Error("Can't find organization by id");
33
39
  }
34
- (0, util_1.log)('Building crowdin client instance', config.logger);
35
- const { token } = yield (0, connection_1.prepareCrowdinClient)(config, credentials);
36
- const { expired, subscribeLink } = yield (0, connection_1.checkSubscription)(config, token, credentials.id, credentials.type);
40
+ logInfo('Building crowdin client instance');
41
+ const { token } = yield (0, connection_1.prepareCrowdinClient)({ config, credentials });
42
+ const { expired, subscribeLink } = yield (0, connection_1.checkSubscription)({
43
+ config,
44
+ token,
45
+ organization: credentials.id,
46
+ accountType: credentials.type,
47
+ });
37
48
  if (expired) {
38
49
  return res.render('subscription', { subscribeLink });
39
50
  }
40
51
  next();
41
- }), config.onError);
52
+ }));
42
53
  }
43
54
  exports.default = handle;
@@ -3,6 +3,7 @@ import { JwtPayload, VerifyOptions } from '@crowdin/crowdin-apps-functions';
3
3
  import { Request } from 'express';
4
4
  import { MySQLStorageConfig } from '../storage/mysql';
5
5
  import { PostgreStorageConfig } from '../storage/postgre';
6
+ import { LogContext, LogErrorFunction, LogFunction } from '../util/logger';
6
7
  export interface ClientConfig extends ImagePath {
7
8
  /**
8
9
  * Authentication Crowdin App type: "authorization_code", "crowdin_app". Default: "crowdin_app"
@@ -48,6 +49,10 @@ export interface ClientConfig extends ImagePath {
48
49
  * app description
49
50
  */
50
51
  description: string;
52
+ /**
53
+ * Set default app permissions
54
+ */
55
+ defaultPermissions?: DefaultPermissions;
51
56
  /**
52
57
  * port where to start express application
53
58
  */
@@ -126,7 +131,7 @@ export interface ClientConfig extends ImagePath {
126
131
  /**
127
132
  * Error interceptor (can be used to log error in centralized place)
128
133
  */
129
- onError?: (error: any) => void;
134
+ onError?: (error: any, context?: LogContext) => void;
130
135
  /**
131
136
  * Disable global error handling of unhandledRejection and uncaughtException events
132
137
  */
@@ -143,6 +148,10 @@ export interface ClientConfig extends ImagePath {
143
148
  filePostImport?: FilePostImportLogic;
144
149
  filePreExport?: FilePreExportLogic;
145
150
  filePostExport?: FilePostExportLogic;
151
+ /**
152
+ * sentry dsn identifier of sentry project
153
+ */
154
+ sentryDsn?: string;
146
155
  }
147
156
  export type Config = ClientConfig & {
148
157
  baseUrl: string;
@@ -470,6 +479,8 @@ export interface CrowdinClientRequest extends Request {
470
479
  crowdinApiClient: Crowdin;
471
480
  crowdinContext: CrowdinContextInfo;
472
481
  subscriptionInfo?: SubscriptionInfo;
482
+ logInfo: LogFunction;
483
+ logError: LogErrorFunction;
473
484
  }
474
485
  export interface CrowdinCredentials {
475
486
  id: string;
@@ -601,6 +612,7 @@ export interface ProcessFileRequest {
601
612
  targetLanguages: LanguagesModel.Language[];
602
613
  strings: ProcessFileString[];
603
614
  stringsUrl: string;
615
+ getRawContent?: (encoding: string) => Promise<string>;
604
616
  }
605
617
  export interface ProcessFileRecord {
606
618
  content?: string;
@@ -874,7 +886,6 @@ export interface UpdateCrowdinWebhookPayloadsArgs {
874
886
  req: Request;
875
887
  }
876
888
  export interface CreateOrUpdateSyncedFilesArgs {
877
- config: Config;
878
889
  req: IntegrationRequest;
879
890
  fileIds: string[];
880
891
  }
@@ -884,4 +895,18 @@ export interface IntegrationSyncedFiles {
884
895
  integrationId: string;
885
896
  crowdinId: string;
886
897
  }
898
+ export declare enum UserPermissions {
899
+ OWNER = "owner",
900
+ MANAGERS = "managers",
901
+ ALL_MEMBERS = "all",
902
+ GUESTS = "guests"
903
+ }
904
+ export declare enum ProjectPermissions {
905
+ OWN = "own",
906
+ RESTRICTED = "restricted"
907
+ }
908
+ export interface DefaultPermissions {
909
+ user?: UserPermissions;
910
+ project?: ProjectPermissions;
911
+ }
887
912
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SyncType = exports.SyncCondition = exports.RequestMethods = exports.Provider = exports.ContextOptionsTypes = exports.ContextOptionsLocations = exports.EditorPanelsMode = exports.ProcessFileJobType = exports.SubscriptionInfoType = exports.AccountType = exports.Scope = exports.AuthenticationType = void 0;
3
+ exports.ProjectPermissions = exports.UserPermissions = exports.SyncType = exports.SyncCondition = exports.RequestMethods = exports.Provider = exports.ContextOptionsTypes = exports.ContextOptionsLocations = exports.EditorPanelsMode = exports.ProcessFileJobType = exports.SubscriptionInfoType = exports.AccountType = exports.Scope = exports.AuthenticationType = void 0;
4
4
  var AuthenticationType;
5
5
  (function (AuthenticationType) {
6
6
  AuthenticationType["CODE"] = "authorization_code";
@@ -91,3 +91,15 @@ var SyncType;
91
91
  SyncType[SyncType["SCHEDULE"] = 1] = "SCHEDULE";
92
92
  SyncType[SyncType["WEBHOOKS"] = 2] = "WEBHOOKS";
93
93
  })(SyncType = exports.SyncType || (exports.SyncType = {}));
94
+ var UserPermissions;
95
+ (function (UserPermissions) {
96
+ UserPermissions["OWNER"] = "owner";
97
+ UserPermissions["MANAGERS"] = "managers";
98
+ UserPermissions["ALL_MEMBERS"] = "all";
99
+ UserPermissions["GUESTS"] = "guests";
100
+ })(UserPermissions = exports.UserPermissions || (exports.UserPermissions = {}));
101
+ var ProjectPermissions;
102
+ (function (ProjectPermissions) {
103
+ ProjectPermissions["OWN"] = "own";
104
+ ProjectPermissions["RESTRICTED"] = "restricted";
105
+ })(ProjectPermissions = exports.ProjectPermissions || (exports.ProjectPermissions = {}));
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.getStorage = exports.initialize = void 0;
13
- const util_1 = require("../util");
13
+ const logger_1 = require("../util/logger");
14
14
  const mysql_1 = require("./mysql");
15
15
  const postgre_1 = require("./postgre");
16
16
  const sqlite_1 = require("./sqlite");
@@ -18,15 +18,15 @@ let storage;
18
18
  function initialize(config) {
19
19
  return __awaiter(this, void 0, void 0, function* () {
20
20
  if (config.postgreConfig) {
21
- (0, util_1.log)('Using PostgreSQL database', config.logger);
21
+ (0, logger_1.log)('Using PostgreSQL database');
22
22
  storage = new postgre_1.PostgreStorage(config.postgreConfig);
23
23
  }
24
24
  else if (config.mysqlConfig) {
25
- (0, util_1.log)('Using MySQL database', config.logger);
25
+ (0, logger_1.log)('Using MySQL database');
26
26
  storage = new mysql_1.MySQLStorage(config.mysqlConfig);
27
27
  }
28
28
  else {
29
- (0, util_1.log)('Using SQLite database', config.logger);
29
+ (0, logger_1.log)('Using SQLite database');
30
30
  storage = new sqlite_1.SQLiteStorage({ dbFolder: config.dbFolder });
31
31
  }
32
32
  yield storage.migrate();
@@ -200,7 +200,7 @@ function addDefaultApiEndpoints(app, config) {
200
200
  * data:
201
201
  * $ref: '#/components/schemas/FileProgress'
202
202
  */
203
- app.get('/file-progress', (0, crowdin_client_1.default)(config), (0, crowdin_file_progress_1.default)(config, config.projectIntegration));
203
+ app.get('/file-progress', (0, crowdin_client_1.default)(config), (0, crowdin_file_progress_1.default)(config.projectIntegration));
204
204
  /**
205
205
  * @openapi
206
206
  * /integration-files:
@@ -222,7 +222,7 @@ function addDefaultApiEndpoints(app, config) {
222
222
  * $ref: '#/components/schemas/IntegrationFiles'
223
223
  *
224
224
  */
225
- app.get('/integration-files', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, integration_data_1.default)(config, config.projectIntegration));
225
+ app.get('/integration-files', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, integration_data_1.default)(config.projectIntegration));
226
226
  /**
227
227
  * @openapi
228
228
  * /crowdin-update:
@@ -289,7 +289,7 @@ function addDefaultApiEndpoints(app, config) {
289
289
  * data:
290
290
  * $ref: '#/components/schemas/SettingsResponse'
291
291
  */
292
- app.get('/settings', (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, settings_1.default)(config));
292
+ app.get('/settings', (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, settings_1.default)());
293
293
  /**
294
294
  * @openapi
295
295
  * /settings:
@@ -338,7 +338,7 @@ function addDefaultApiEndpoints(app, config) {
338
338
  * - { $ref: '#/components/schemas/CrowdinSyncSettingsResponse' }
339
339
  * - { $ref: '#/components/schemas/IntegrationSyncSettingsResponse' }
340
340
  */
341
- app.get('/sync-settings', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, sync_settings_1.default)(config));
341
+ app.get('/sync-settings', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, sync_settings_1.default)());
342
342
  /**
343
343
  * @openapi
344
344
  * /sync-settings:
@@ -1,10 +1,19 @@
1
1
  import Crowdin from '@crowdin/crowdin-api-client';
2
2
  import { AccountType, Config, CrowdinCredentials, IntegrationCredentials, IntegrationLogic, SubscriptionInfo } from '../models';
3
- export declare function prepareCrowdinClient(config: Config, credentials: CrowdinCredentials, autoRenew?: boolean): Promise<{
3
+ export declare function prepareCrowdinClient({ config, credentials, autoRenew, }: {
4
+ config: Config;
5
+ credentials: CrowdinCredentials;
6
+ autoRenew?: boolean;
7
+ }): Promise<{
4
8
  client: Crowdin;
5
9
  token: string;
6
10
  }>;
7
11
  export declare function prepareIntegrationCredentials(config: Config, integration: IntegrationLogic, integrationCredentials: IntegrationCredentials): Promise<any>;
8
12
  export declare function clearCache(organization: string): void;
9
13
  export declare function isAppFree(config: Config): boolean;
10
- export declare function checkSubscription(config: Config, token: string, organization: string, accountType: AccountType): Promise<SubscriptionInfo>;
14
+ export declare function checkSubscription({ config, token, organization, accountType, }: {
15
+ config: Config;
16
+ token: string;
17
+ organization: string;
18
+ accountType: AccountType;
19
+ }): Promise<SubscriptionInfo>;
@@ -20,6 +20,7 @@ const _1 = require(".");
20
20
  const models_1 = require("../models");
21
21
  const storage_1 = require("../storage");
22
22
  const axios_2 = require("./axios");
23
+ const logger_1 = require("./logger");
23
24
  const axiosCustom = new axios_2.AxiosProvider().axios;
24
25
  function refreshToken(config, credentials) {
25
26
  var _a, _b;
@@ -53,7 +54,7 @@ function refreshToken(config, credentials) {
53
54
  };
54
55
  });
55
56
  }
56
- function prepareCrowdinClient(config, credentials, autoRenew = false) {
57
+ function prepareCrowdinClient({ config, credentials, autoRenew = false, }) {
57
58
  var _a, _b;
58
59
  return __awaiter(this, void 0, void 0, function* () {
59
60
  //2 min as an extra buffer
@@ -206,9 +207,9 @@ function prepareCrowdinClient(config, credentials, autoRenew = false) {
206
207
  exports.prepareCrowdinClient = prepareCrowdinClient;
207
208
  function refreshCrowdinCreds({ config, credentials }) {
208
209
  return __awaiter(this, void 0, void 0, function* () {
209
- (0, _1.log)('Crowdin credentials have expired. Requesting a new credentials', config.logger);
210
+ (0, logger_1.log)('Crowdin credentials have expired. Requesting a new credentials');
210
211
  const newCredentials = yield refreshToken(config, credentials);
211
- (0, _1.log)('Saving updated crowdin credentials in the database', config.logger);
212
+ (0, logger_1.log)('Saving updated crowdin credentials in the database');
212
213
  const newCrowdinCredentials = {
213
214
  id: credentials.id,
214
215
  appSecret: credentials.appSecret,
@@ -234,13 +235,13 @@ function prepareIntegrationCredentials(config, integration, integrationCredentia
234
235
  return __awaiter(this, void 0, void 0, function* () {
235
236
  const credentials = JSON.parse((0, _1.decryptData)(config, integrationCredentials.credentials));
236
237
  if ((_a = integration.oauthLogin) === null || _a === void 0 ? void 0 : _a.refresh) {
237
- (0, _1.log)('Checking if integration credentials need to be refreshed', config.logger);
238
+ (0, logger_1.log)('Checking if integration credentials need to be refreshed');
238
239
  const oauthLogin = integration.oauthLogin;
239
240
  const { expireIn } = credentials;
240
241
  //2 min as an extra buffer
241
242
  const isExpired = expireIn - 120 < Date.now() / 1000;
242
243
  if (isExpired) {
243
- (0, _1.log)('Integration credentials have expired. Requesting a new credentials', config.logger);
244
+ (0, logger_1.log)('Integration credentials have expired. Requesting a new credentials');
244
245
  let newCredentials;
245
246
  if (oauthLogin.performRefreshTokenRequest) {
246
247
  newCredentials = yield oauthLogin.performRefreshTokenRequest(credentials);
@@ -264,7 +265,7 @@ function prepareIntegrationCredentials(config, integration, integrationCredentia
264
265
  if (newCredentials[((_g = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _g === void 0 ? void 0 : _g.refreshToken) || 'refresh_token']) {
265
266
  credentials.refreshToken = newCredentials[((_h = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _h === void 0 ? void 0 : _h.refreshToken) || 'refresh_token'];
266
267
  }
267
- (0, _1.log)('Saving updated integration credentials in the database', config.logger);
268
+ (0, logger_1.log)('Saving updated integration credentials in the database');
268
269
  yield (0, storage_1.getStorage)().updateIntegrationCredentials(integrationCredentials.id, (0, _1.encryptData)(config, JSON.stringify(credentials)));
269
270
  }
270
271
  }
@@ -304,21 +305,21 @@ function validateSubscription(date) {
304
305
  const daysLeft = Math.round((date.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
305
306
  return { expired, daysLeft };
306
307
  }
307
- function checkSubscription(config, token, organization, accountType) {
308
+ function checkSubscription({ config, token, organization, accountType, }) {
308
309
  var _a, _b, _c, _d, _e, _f, _g;
309
310
  return __awaiter(this, void 0, void 0, function* () {
310
311
  if (isAppFree(config)) {
311
312
  return { expired: false };
312
313
  }
313
- (0, _1.log)('Checking subscription plan', config.logger);
314
+ (0, logger_1.log)('Checking subscription plan');
314
315
  const appIdentifier = config.identifier;
315
316
  const cacheEntry = getFromCache(organization, appIdentifier);
316
317
  if (cacheEntry) {
317
318
  const { cacheValidUntil, validUntil, subscribeLink, type } = cacheEntry;
318
319
  if (cacheValidUntil.getTime() > Date.now()) {
319
- (0, _1.log)(`Loaded data from cache. Subscription is valid until ${validUntil.toISOString()}`, config.logger);
320
+ (0, logger_1.log)(`Loaded data from cache. Subscription is valid until ${validUntil.toISOString()}`);
320
321
  const { expired, daysLeft } = validateSubscription(new Date(validUntil));
321
- (0, _1.log)(`expired ${expired}`, config.logger);
322
+ (0, logger_1.log)(`expired ${expired}`);
322
323
  return { expired, subscribeLink, daysLeft, type };
323
324
  }
324
325
  }
@@ -329,16 +330,16 @@ function checkSubscription(config, token, organization, accountType) {
329
330
  token,
330
331
  baseUrl: (_a = config.crowdinUrls) === null || _a === void 0 ? void 0 : _a.subscriptionUrl,
331
332
  });
332
- (0, _1.log)(`Recieved subscription info. ${JSON.stringify(subscription)}`, config.logger);
333
+ (0, logger_1.log)(`Recieved subscription info. ${JSON.stringify(subscription)}`);
333
334
  const { expired, daysLeft } = validateSubscription(new Date(subscription.expires));
334
- (0, _1.log)(`expired ${expired}`, config.logger);
335
+ (0, logger_1.log)(`expired ${expired}`);
335
336
  addToCache(organization, appIdentifier, new Date(subscription.expires), models_1.SubscriptionInfoType.SUBSCRIPTION, (_b = config.pricing) === null || _b === void 0 ? void 0 : _b.cachingSeconds);
336
337
  return { expired, daysLeft, type: models_1.SubscriptionInfoType.SUBSCRIPTION };
337
338
  }
338
339
  catch (e) {
339
340
  if (e instanceof crowdin_apps_functions_1.PaymentRequiredError) {
340
341
  const { initializedAt, subscribeLink } = e;
341
- (0, _1.log)(`Recieved 402 payment error. initializedAt ${initializedAt}`, config.logger);
342
+ (0, logger_1.log)(`Recieved 402 payment error. initializedAt ${initializedAt}`);
342
343
  //default 2 weeks
343
344
  const defaultSubscriptionPlan = 14;
344
345
  let days;
@@ -348,11 +349,11 @@ function checkSubscription(config, token, organization, accountType) {
348
349
  else {
349
350
  days = ((_e = config.pricing) === null || _e === void 0 ? void 0 : _e.trialCrowdin) || ((_f = config.pricing) === null || _f === void 0 ? void 0 : _f.trial) || defaultSubscriptionPlan;
350
351
  }
351
- (0, _1.log)(`Subscriptino trial plan ${days} days`, config.logger);
352
+ (0, logger_1.log)(`Subscriptino trial plan ${days} days`);
352
353
  const date = new Date(initializedAt);
353
354
  date.setDate(date.getDate() + days);
354
355
  const { expired, daysLeft } = validateSubscription(date);
355
- (0, _1.log)(`expired ${expired}`, config.logger);
356
+ (0, logger_1.log)(`expired ${expired}`);
356
357
  addToCache(organization, appIdentifier, new Date(date), models_1.SubscriptionInfoType.TRIAL, (_g = config.pricing) === null || _g === void 0 ? void 0 : _g.cachingSeconds, subscribeLink);
357
358
  return { expired, subscribeLink, daysLeft, type: models_1.SubscriptionInfoType.TRIAL };
358
359
  }
@@ -362,7 +363,7 @@ function checkSubscription(config, token, organization, accountType) {
362
363
  else {
363
364
  console.error(e);
364
365
  }
365
- (0, _1.log)('Recieved http error from subscription request. Returning expired=false', config.logger);
366
+ (0, logger_1.log)('Recieved http error from subscription request. Returning expired=false');
366
367
  return { expired: false };
367
368
  }
368
369
  });
package/out/util/cron.js CHANGED
@@ -34,21 +34,30 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
35
  exports.createOrUpdateSyncSettings = exports.skipFoldersFromIntegrationRequest = exports.filesCron = exports.runJob = void 0;
36
36
  const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
37
- const _1 = require(".");
38
37
  const models_1 = require("../models");
39
38
  const storage_1 = require("../storage");
40
39
  const connection_1 = require("./connection");
41
40
  const defaults_1 = require("./defaults");
42
41
  const file_snapshot_1 = require("./file-snapshot");
42
+ const logger_1 = require("./logger");
43
43
  function runJob(config, integration, job) {
44
44
  return __awaiter(this, void 0, void 0, function* () {
45
- (0, _1.log)(`Starting cron job with expression [${job.expression}]`, config.logger);
45
+ (0, logger_1.log)(`Starting cron job with expression [${job.expression}]`);
46
46
  const crowdinCredentialsList = yield (0, storage_1.getStorage)().getAllCrowdinCredentials();
47
47
  yield Promise.all(crowdinCredentialsList.map((crowdinCredentials) => __awaiter(this, void 0, void 0, function* () {
48
- const { token, client: crowdinClient } = yield (0, connection_1.prepareCrowdinClient)(config, crowdinCredentials, true);
49
- const { expired } = yield (0, connection_1.checkSubscription)(config, token, crowdinCredentials.id, crowdinCredentials.type);
48
+ const { token, client: crowdinClient } = yield (0, connection_1.prepareCrowdinClient)({
49
+ config,
50
+ credentials: crowdinCredentials,
51
+ autoRenew: true,
52
+ });
53
+ const { expired } = yield (0, connection_1.checkSubscription)({
54
+ config,
55
+ token,
56
+ organization: crowdinCredentials.id,
57
+ accountType: crowdinCredentials.type,
58
+ });
50
59
  if (expired) {
51
- (0, _1.log)(`Subscription expired. Skipping job [${job.expression}] for organization ${crowdinCredentials.id}`);
60
+ (0, logger_1.log)(`Subscription expired. Skipping job [${job.expression}] for organization ${crowdinCredentials.id}`);
52
61
  return;
53
62
  }
54
63
  const integrationCredentialsList = yield (0, storage_1.getStorage)().getAllIntegrationCredentials(crowdinCredentials.id);
@@ -57,18 +66,18 @@ function runJob(config, integration, job) {
57
66
  const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
58
67
  const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient, projectId);
59
68
  const intConfig = integrationCredentials.config ? JSON.parse(integrationCredentials.config) : undefined;
60
- (0, _1.log)(`Executing task for cron job with expression [${job.expression}] for project ${projectId}`, config.logger);
69
+ (0, logger_1.log)(`Executing task for cron job with expression [${job.expression}] for project ${projectId}`);
61
70
  yield job.task(projectId, crowdinClient, apiCredentials, rootFolder, intConfig);
62
- (0, _1.log)(`Task for cron job with expression [${job.expression}] for project ${projectId} completed`, config.logger);
71
+ (0, logger_1.log)(`Task for cron job with expression [${job.expression}] for project ${projectId} completed`);
63
72
  }
64
73
  })));
65
- (0, _1.log)(`Cron job with expression [${job.expression}] completed`, config.logger);
74
+ (0, logger_1.log)(`Cron job with expression [${job.expression}] completed`);
66
75
  });
67
76
  }
68
77
  exports.runJob = runJob;
69
78
  function filesCron(config, integration, period) {
70
79
  return __awaiter(this, void 0, void 0, function* () {
71
- (0, _1.log)(`Starting files cron job with period [${period}]`, config.logger);
80
+ (0, logger_1.log)(`Starting files cron job with period [${period}]`);
72
81
  const syncSettingsList = yield (0, storage_1.getStorage)().getAllSyncSettingsByType('schedule');
73
82
  yield Promise.all(syncSettingsList.map((syncSettings) => __awaiter(this, void 0, void 0, function* () {
74
83
  var _a;
@@ -86,10 +95,19 @@ function filesCron(config, integration, period) {
86
95
  return;
87
96
  }
88
97
  const projectId = crowdinAppFunctions.getProjectId(integrationCredentials.id);
89
- const { client: crowdinClient, token } = yield (0, connection_1.prepareCrowdinClient)(config, crowdinCredentials, true);
90
- const { expired } = yield (0, connection_1.checkSubscription)(config, token, crowdinCredentials.id, crowdinCredentials.type);
98
+ const { client: crowdinClient, token } = yield (0, connection_1.prepareCrowdinClient)({
99
+ config,
100
+ credentials: crowdinCredentials,
101
+ autoRenew: true,
102
+ });
103
+ const { expired } = yield (0, connection_1.checkSubscription)({
104
+ config,
105
+ token,
106
+ organization: crowdinCredentials.id,
107
+ accountType: crowdinCredentials.type,
108
+ });
91
109
  if (expired) {
92
- (0, _1.log)(`Subscription expired. Skipping job [${period}] for organization ${crowdinCredentials.id}`);
110
+ (0, logger_1.log)(`Subscription expired. Skipping job [${period}] for organization ${crowdinCredentials.id}`);
93
111
  return;
94
112
  }
95
113
  const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient, projectId);
@@ -115,10 +133,10 @@ function filesCron(config, integration, period) {
115
133
  const filesToProcess = all
116
134
  ? crowdinFiles
117
135
  : yield getOnlyTranslatedOrApprovedFiles(config, projectId, crowdinFiles, crowdinClient, onlyApproved, onlyTranslated);
118
- (0, _1.log)(`Executing updateIntegration task for files cron job with period [${period}] for project ${projectId}.Files ${Object.keys(filesToProcess).length}`, config.logger);
136
+ (0, logger_1.log)(`Executing updateIntegration task for files cron job with period [${period}] for project ${projectId}.Files ${Object.keys(filesToProcess).length}`);
119
137
  if (!all) {
120
138
  if (Object.keys(filesToProcess).length === 0) {
121
- (0, _1.log)(`There is no ${onlyApproved ? 'approved' : 'translated'} file`, config.logger);
139
+ (0, logger_1.log)(`There is no ${onlyApproved ? 'approved' : 'translated'} file`);
122
140
  return;
123
141
  }
124
142
  }
@@ -129,7 +147,7 @@ function filesCron(config, integration, period) {
129
147
  const currentFileSnapshot = yield (0, file_snapshot_1.getCrowdinSnapshot)(config, integration, crowdinClient, projectId, intConfig);
130
148
  yield (0, storage_1.getStorage)().updateFilesSnapshot(JSON.stringify(currentFileSnapshot), syncSettings.integrationId, syncSettings.crowdinId, syncSettings.provider);
131
149
  }
132
- (0, _1.log)(`updateIntegration task for files cron job with period [${period}] for project ${projectId} completed`, config.logger);
150
+ (0, logger_1.log)(`updateIntegration task for files cron job with period [${period}] for project ${projectId} completed`);
133
151
  }
134
152
  else {
135
153
  const allIntFiles = [...files, ...newFiles].map((file) => (Object.assign({ id: file.id, name: file.name, parentId: file.parent_id || file.parentId,
@@ -138,7 +156,7 @@ function filesCron(config, integration, period) {
138
156
  // eslint-disable-next-line @typescript-eslint/camelcase
139
157
  node_type: file.nodeType || file.node_type }, (file.type ? { type: file.type } : {}))));
140
158
  const intFiles = allIntFiles.filter((file) => 'type' in file);
141
- (0, _1.log)(`Executing updateCrowdin task for files cron job with period [${period}] for project ${projectId}. Files ${intFiles.length}`, config.logger);
159
+ (0, logger_1.log)(`Executing updateCrowdin task for files cron job with period [${period}] for project ${projectId}. Files ${intFiles.length}`);
142
160
  const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
143
161
  yield integration.updateCrowdin(projectId, crowdinClient, apiCredentials, intFiles, rootFolder, intConfig);
144
162
  const newSyncSettingsFiels = allIntFiles.map((file) => (Object.assign(Object.assign({}, file), { schedule: true, sync: false })));
@@ -147,16 +165,16 @@ function filesCron(config, integration, period) {
147
165
  const currentFileSnapshot = yield (0, file_snapshot_1.getIntegrationSnapshot)(integration, apiCredentials, intConfig);
148
166
  yield (0, storage_1.getStorage)().updateFilesSnapshot(JSON.stringify(currentFileSnapshot), syncSettings.integrationId, syncSettings.crowdinId, syncSettings.provider);
149
167
  }
150
- (0, _1.log)(`updateCrowdin task for files cron job with period [${period}] for project ${projectId} completed`, config.logger);
168
+ (0, logger_1.log)(`updateCrowdin task for files cron job with period [${period}] for project ${projectId} completed`);
151
169
  }
152
170
  })));
153
- (0, _1.log)(`Files cron job with period [${period}] completed`, config.logger);
171
+ (0, logger_1.log)(`Files cron job with period [${period}] completed`);
154
172
  });
155
173
  }
156
174
  exports.filesCron = filesCron;
157
175
  function getOnlyTranslatedOrApprovedFiles(config, projectId, crowdinFiles, crowdinClient, onlyApproved, onlyTranslated) {
158
176
  return __awaiter(this, void 0, void 0, function* () {
159
- (0, _1.log)(`Filtering files to process only ${onlyApproved ? 'approved' : 'translated'} files`, config.logger);
177
+ (0, logger_1.log)(`Filtering files to process only ${onlyApproved ? 'approved' : 'translated'} files`);
160
178
  const filesInfo = yield Promise.all(Object.keys(crowdinFiles).map((fileId) => __awaiter(this, void 0, void 0, function* () {
161
179
  const res = yield crowdinClient.translationStatusApi
162
180
  .withFetchAll()
@@ -180,26 +198,26 @@ function getOnlyTranslatedOrApprovedFiles(config, projectId, crowdinFiles, crowd
180
198
  }
181
199
  if (onlyTranslated) {
182
200
  if (languageInfo.translationProgress === 100) {
183
- (0, _1.log)(`File ${fileId} is fully translated for language ${language}`, config.logger);
201
+ (0, logger_1.log)(`File ${fileId} is fully translated for language ${language}`);
184
202
  if (!filteredFiles[fileId]) {
185
203
  filteredFiles[fileId] = [];
186
204
  }
187
205
  filteredFiles[fileId].push(language);
188
206
  }
189
207
  else {
190
- (0, _1.log)(`File ${fileId} is not fully translated for language ${language}, progress ${languageInfo.translationProgress}`, config.logger);
208
+ (0, logger_1.log)(`File ${fileId} is not fully translated for language ${language}, progress ${languageInfo.translationProgress}`);
191
209
  }
192
210
  }
193
211
  if (onlyApproved) {
194
212
  if (languageInfo.approvalProgress === 100) {
195
- (0, _1.log)(`File ${fileId} is fully approved for language ${language}`, config.logger);
213
+ (0, logger_1.log)(`File ${fileId} is fully approved for language ${language}`);
196
214
  if (!filteredFiles[fileId]) {
197
215
  filteredFiles[fileId] = [];
198
216
  }
199
217
  filteredFiles[fileId].push(language);
200
218
  }
201
219
  else {
202
- (0, _1.log)(`File ${fileId} is not fully approved for language ${language}, progress ${languageInfo.approvalProgress}`, config.logger);
220
+ (0, logger_1.log)(`File ${fileId} is not fully approved for language ${language}, progress ${languageInfo.approvalProgress}`);
203
221
  }
204
222
  }
205
223
  });
@@ -238,11 +256,11 @@ function createOrUpdateSyncSettings(config, req, files, provider, onlyCreate = f
238
256
  return __awaiter(this, void 0, void 0, function* () {
239
257
  const existingSettings = yield (0, storage_1.getStorage)().getSyncSettings(req.crowdinContext.clientId, req.crowdinContext.crowdinId, 'schedule', provider);
240
258
  if (!existingSettings) {
241
- (0, _1.log)(`Saving sync settings for type schedule and provider ${provider} ${JSON.stringify(files, null, 2)}`, config.logger);
259
+ (0, logger_1.log)(`Saving sync settings for type schedule and provider ${provider} ${JSON.stringify(files, null, 2)}`);
242
260
  yield (0, storage_1.getStorage)().saveSyncSettings(JSON.stringify(files), req.crowdinContext.clientId, req.crowdinContext.crowdinId, 'schedule', provider);
243
261
  }
244
262
  else if (!onlyCreate) {
245
- (0, _1.log)(`Updating sync settings for type schedule and provider ${provider} ${JSON.stringify(files, null, 2)}`, config.logger);
263
+ (0, logger_1.log)(`Updating sync settings for type schedule and provider ${provider} ${JSON.stringify(files, null, 2)}`);
246
264
  yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(files), req.crowdinContext.clientId, req.crowdinContext.crowdinId, 'schedule', provider);
247
265
  }
248
266
  });
@@ -290,10 +290,11 @@ function convertClientConfig(clientConfig) {
290
290
  const clientId = clientConfig.clientId || process.env.CROWDIN_CLIENT_ID;
291
291
  const clientSecret = clientConfig.clientSecret || process.env.CROWDIN_CLIENT_SECRET;
292
292
  const port = clientConfig.port || process.env.PORT || 3000;
293
+ const sentryDsn = clientConfig.sentryDsn || process.env.SENTRY_DSN;
293
294
  if (!baseUrl || !clientId || !clientSecret) {
294
295
  throw new Error('One of following parameters are not defined [baseUrl, clientId, clientSecret]');
295
296
  }
296
- return Object.assign(Object.assign({}, clientConfig), { baseUrl: baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl, clientId,
297
+ return Object.assign(Object.assign({}, clientConfig), { sentryDsn, baseUrl: baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl, clientId,
297
298
  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') });
298
299
  }
299
300
  exports.convertClientConfig = convertClientConfig;
@@ -1,5 +1,5 @@
1
- import { Config, GetAllNewFilesArgs, IntegrationLogic, IntegrationRequest, Provider, TreeItem, UpdateIntegrationRequest } from '../models';
2
1
  import Crowdin from '@crowdin/crowdin-api-client';
2
+ import { Config, GetAllNewFilesArgs, IntegrationLogic, IntegrationRequest, Provider, TreeItem, UpdateIntegrationRequest } from '../models';
3
3
  export declare function getFileDiff(currentFiles: TreeItem[], savedFiles: TreeItem[]): TreeItem[];
4
4
  export declare function getAllNewFiles(args: GetAllNewFilesArgs): Promise<TreeItem[] | UpdateIntegrationRequest>;
5
5
  export declare function getCrowdinSnapshot(config: Config, integration: IntegrationLogic, crowdinApiClient: Crowdin, projectId: number, integrationSettings: any): Promise<TreeItem[]>;