@crowdin/app-project-module 0.98.0-cf-0 → 0.98.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 (86) hide show
  1. package/out/index.js +6 -17
  2. package/out/middlewares/integration-credentials.js +1 -4
  3. package/out/middlewares/render-ui-module.d.ts +3 -3
  4. package/out/middlewares/render-ui-module.js +13 -9
  5. package/out/middlewares/ui-module.js +1 -4
  6. package/out/modules/about.d.ts +1 -1
  7. package/out/modules/about.js +2 -8
  8. package/out/modules/ai-prompt-provider/index.js +2 -4
  9. package/out/modules/ai-provider/index.js +2 -4
  10. package/out/modules/ai-tools/index.js +1 -1
  11. package/out/modules/context-menu/index.js +2 -2
  12. package/out/modules/custom-mt/index.js +1 -3
  13. package/out/modules/custom-spell-check/index.js +4 -4
  14. package/out/modules/editor-right-panel/index.js +1 -1
  15. package/out/modules/external-qa-check/index.js +2 -2
  16. package/out/modules/integration/handlers/crowdin-files.js +6 -4
  17. package/out/modules/integration/handlers/crowdin-update.js +18 -4
  18. package/out/modules/integration/handlers/integration-data.js +17 -13
  19. package/out/modules/integration/handlers/main.js +3 -13
  20. package/out/modules/integration/handlers/oauth-login.js +2 -10
  21. package/out/modules/integration/index.js +21 -27
  22. package/out/modules/integration/types.d.ts +11 -1
  23. package/out/modules/integration/util/defaults.js +51 -45
  24. package/out/modules/integration/util/files.d.ts +1 -0
  25. package/out/modules/integration/util/files.js +52 -4
  26. package/out/modules/integration/util/job.d.ts +1 -1
  27. package/out/modules/integration/util/job.js +3 -2
  28. package/out/modules/integration/util/types.d.ts +2 -0
  29. package/out/modules/modal/index.js +2 -2
  30. package/out/modules/organization-menu/index.js +4 -6
  31. package/out/modules/organization-settings-menu/index.js +4 -6
  32. package/out/modules/profile-resources-menu/index.js +4 -6
  33. package/out/modules/profile-settings-menu/index.js +4 -6
  34. package/out/modules/project-menu/index.js +1 -1
  35. package/out/modules/project-menu-crowdsource/index.js +1 -1
  36. package/out/modules/project-reports/index.js +2 -4
  37. package/out/modules/project-tools/index.js +2 -4
  38. package/out/modules/workflow-step-type/index.js +2 -3
  39. package/out/storage/index.js +1 -8
  40. package/out/storage/mysql.d.ts +1 -1
  41. package/out/storage/mysql.js +9 -1
  42. package/out/storage/postgre.d.ts +1 -1
  43. package/out/storage/postgre.js +11 -4
  44. package/out/storage/sqlite.d.ts +1 -1
  45. package/out/storage/sqlite.js +10 -4
  46. package/out/types.d.ts +0 -10
  47. package/out/util/handlebars.d.ts +1 -0
  48. package/out/util/handlebars.js +46 -0
  49. package/out/util/index.d.ts +0 -1
  50. package/out/util/index.js +2 -8
  51. package/out/views/about.handlebars +102 -0
  52. package/out/views/error.handlebars +54 -0
  53. package/out/views/form.handlebars +30 -0
  54. package/out/views/install.handlebars +16 -0
  55. package/out/views/login.handlebars +331 -0
  56. package/out/views/main.handlebars +1901 -0
  57. package/out/views/oauth.handlebars +11 -0
  58. package/out/views/partials/head.handlebars +53 -0
  59. package/out/views/subscription.handlebars +26 -0
  60. package/package.json +11 -12
  61. package/out/storage/d1.d.ts +0 -99
  62. package/out/storage/d1.js +0 -769
  63. package/out/util/jsx-renderer.d.ts +0 -6
  64. package/out/util/jsx-renderer.js +0 -13
  65. package/out/util/static-files.d.ts +0 -19
  66. package/out/util/static-files.js +0 -80
  67. package/out/views/AboutPage.d.ts +0 -9
  68. package/out/views/AboutPage.js +0 -79
  69. package/out/views/ErrorPage.d.ts +0 -18
  70. package/out/views/ErrorPage.js +0 -56
  71. package/out/views/FormPage.d.ts +0 -13
  72. package/out/views/FormPage.js +0 -27
  73. package/out/views/InstallPage.d.ts +0 -10
  74. package/out/views/InstallPage.js +0 -22
  75. package/out/views/LoginPage.d.ts +0 -33
  76. package/out/views/LoginPage.js +0 -199
  77. package/out/views/MainPage.d.ts +0 -79
  78. package/out/views/MainPage.js +0 -1613
  79. package/out/views/OAuthPage.d.ts +0 -7
  80. package/out/views/OAuthPage.js +0 -17
  81. package/out/views/SubscriptionPage.d.ts +0 -7
  82. package/out/views/SubscriptionPage.js +0 -26
  83. package/out/views/index.d.ts +0 -13
  84. package/out/views/index.js +0 -25
  85. package/out/views/layout/Head.d.ts +0 -9
  86. package/out/views/layout/Head.js +0 -54
package/out/index.js CHANGED
@@ -50,11 +50,11 @@ const subscription_paid_1 = __importDefault(require("./modules/subscription-paid
50
50
  const uninstall_1 = __importDefault(require("./modules/uninstall"));
51
51
  const status_1 = __importDefault(require("./modules/status"));
52
52
  const storage = __importStar(require("./storage"));
53
- const d1_1 = require("./storage/d1");
54
53
  const types_1 = require("./types");
55
54
  const util_1 = require("./util");
56
55
  const form_schema_1 = require("./util/form-schema");
57
56
  const connection_1 = require("./util/connection");
57
+ const handlebars_1 = require("./util/handlebars");
58
58
  const logger = __importStar(require("./util/logger"));
59
59
  const logger_1 = require("./util/logger");
60
60
  const terminus_express_1 = __importDefault(require("./util/terminus-express"));
@@ -63,7 +63,6 @@ const credentials_masker_1 = require("./util/credentials-masker");
63
63
  Object.defineProperty(exports, "getRequestCredentialsMasker", { enumerable: true, get: function () { return credentials_masker_1.getRequestCredentialsMasker; } });
64
64
  Object.defineProperty(exports, "postRequestCredentialsMasker", { enumerable: true, get: function () { return credentials_masker_1.postRequestCredentialsMasker; } });
65
65
  Object.defineProperty(exports, "maskKey", { enumerable: true, get: function () { return credentials_masker_1.maskKey; } });
66
- const static_files_1 = require("./util/static-files");
67
66
  //apps
68
67
  const apiApp = __importStar(require("./modules/api"));
69
68
  const contextMenuApp = __importStar(require("./modules/context-menu"));
@@ -139,19 +138,6 @@ function addCrowdinEndpoints(app, clientConfig) {
139
138
  }
140
139
  storage.initialize(config);
141
140
  logger.initialize(config);
142
- // Middleware to ensure D1 migration before handling requests
143
- app.use((req, res, next) => __awaiter(this, void 0, void 0, function* () {
144
- try {
145
- const storageInstance = storage.getStorage();
146
- if (storageInstance instanceof d1_1.D1Storage) {
147
- yield storageInstance.ensureMigrated();
148
- }
149
- next();
150
- }
151
- catch (error) {
152
- next(error);
153
- }
154
- }));
155
141
  app.use((req, res, next) => {
156
142
  if (config.webhooks && req.path === '/webhooks') {
157
143
  return terminus_express_1.default.raw({ type: '*/*', limit: '50mb' })(req, res, next);
@@ -165,8 +151,11 @@ function addCrowdinEndpoints(app, clientConfig) {
165
151
  app.use(logsFormatter.contextResolverMiddleware());
166
152
  app.use(logsFormatter.expressMiddleware());
167
153
  }
168
- app.use('/assets', (0, static_files_1.serveStatic)(config, 'static'));
169
- app.get((0, util_1.getLogoUrl)(), (0, static_files_1.serveFile)(config, config.imagePath));
154
+ app.use('/assets', terminus_express_1.default.static((0, path_1.join)(__dirname, 'static')));
155
+ app.set('views', (0, path_1.join)(__dirname, 'views'));
156
+ app.engine('handlebars', handlebars_1.engine);
157
+ app.set('view engine', 'handlebars');
158
+ app.get((0, util_1.getLogoUrl)(), (req, res) => res.sendFile(config.imagePath));
170
159
  app.get('/manifest.json', json_response_1.default, (0, manifest_1.default)(config));
171
160
  app.get('/', (0, about_1.default)(config));
172
161
  if (((_a = config === null || config === void 0 ? void 0 : config.enableStatusPage) === null || _a === void 0 ? void 0 : _a.database) || ((_b = config === null || config === void 0 ? void 0 : config.enableStatusPage) === null || _b === void 0 ? void 0 : _b.filesystem)) {
@@ -37,7 +37,6 @@ const util_1 = require("../util");
37
37
  const connection_1 = require("../util/connection");
38
38
  const logger_1 = require("../util/logger");
39
39
  const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
40
- const views_1 = require("../views");
41
40
  function handle(config, integration, optional = false) {
42
41
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
43
42
  let clientId = req.crowdinContext.clientId;
@@ -90,9 +89,7 @@ function handle(config, integration, optional = false) {
90
89
  else {
91
90
  (0, logger_1.temporaryErrorDebug)('Access denied: integration-credentials', req);
92
91
  }
93
- const html = (0, util_1.renderJSX)(views_1.ErrorPage, errorOptions);
94
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
95
- return res.send(html);
92
+ return res.render('error', errorOptions);
96
93
  }
97
94
  try {
98
95
  req.integrationCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
@@ -1,4 +1,4 @@
1
1
  /// <reference types="qs" />
2
- import { Request, Response } from 'express';
3
- import { UiModule, Config, UnauthorizedConfig } from '../types';
4
- export default function handle(moduleConfig: UiModule, config: Config | UnauthorizedConfig): (req: import("../types").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;
2
+ import express from 'express';
3
+ import { UiModule } from '../types';
4
+ export default function handle(moduleConfig: UiModule): (req: import("../types").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;
@@ -8,24 +8,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
+ const express_1 = __importDefault(require("express"));
12
16
  const util_1 = require("../util");
13
- const static_files_1 = require("../util/static-files");
14
- const views_1 = require("../views");
15
- function handle(moduleConfig, config) {
17
+ function handle(moduleConfig) {
16
18
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
17
19
  if (moduleConfig.formSchema) {
18
- const html = (0, util_1.renderJSX)(views_1.FormPage, {
19
- formGetDataUrl: moduleConfig.formGetDataUrl || `/api/${moduleConfig.key}/form-data`,
20
- formPostDataUrl: moduleConfig.formPostDataUrl || `/api/${moduleConfig.key}/form-data`,
20
+ return res.render('form', {
21
+ formGetDataUrl: moduleConfig.formGetDataUrl
22
+ ? moduleConfig.formGetDataUrl
23
+ : `/api/${moduleConfig.key}/form-data`,
24
+ formPostDataUrl: moduleConfig.formPostDataUrl
25
+ ? moduleConfig.formPostDataUrl
26
+ : `/api/${moduleConfig.key}/form-data`,
21
27
  formSchema: JSON.stringify(moduleConfig.formSchema),
22
28
  formUiSchema: moduleConfig.formUiSchema ? JSON.stringify(moduleConfig.formUiSchema) : '{}',
23
29
  });
24
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
25
- return res.send(html);
26
30
  }
27
31
  if (moduleConfig.uiPath) {
28
- return (0, static_files_1.serveStatic)(config, moduleConfig.uiPath)(req, res, next);
32
+ return express_1.default.static(moduleConfig.uiPath)(req, res, next);
29
33
  }
30
34
  throw new Error('uiPath or formSchema should be provided for module');
31
35
  }));
@@ -15,7 +15,6 @@ const util_1 = require("../util");
15
15
  const connection_1 = require("../util/connection");
16
16
  const logger_1 = require("../util/logger");
17
17
  const subscription_1 = require("../util/subscription");
18
- const views_1 = require("../views");
19
18
  function handle({ config, allowUnauthorized = false, moduleType, }) {
20
19
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
21
20
  if (allowUnauthorized) {
@@ -58,9 +57,7 @@ function handle({ config, allowUnauthorized = false, moduleType, }) {
58
57
  accountType: credentials.type,
59
58
  });
60
59
  if (expired) {
61
- const html = (0, util_1.renderJSX)(views_1.SubscriptionPage, { subscribeLink });
62
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
63
- return res.send(html);
60
+ return res.render('subscription', { subscribeLink });
64
61
  }
65
62
  next();
66
63
  }));
@@ -6,4 +6,4 @@ export declare function getAboutPageOptions(config: Config | UnauthorizedConfig)
6
6
  manifest: string;
7
7
  storeLink: string;
8
8
  }>;
9
- export default function handle(config: Config | UnauthorizedConfig): (req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>;
9
+ export default function handle(config: Config | UnauthorizedConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
@@ -16,8 +16,6 @@ exports.getAboutPageOptions = void 0;
16
16
  const axios_1 = __importDefault(require("axios"));
17
17
  const util_1 = require("../util");
18
18
  const crowdin_client_1 = require("../middlewares/crowdin-client");
19
- const jsx_renderer_1 = require("../util/jsx-renderer");
20
- const views_1 = require("../views");
21
19
  function getAboutPageOptions(config) {
22
20
  return __awaiter(this, void 0, void 0, function* () {
23
21
  let detailPage = '';
@@ -45,9 +43,7 @@ function handle(config) {
45
43
  const jwtToken = (0, crowdin_client_1.getToken)(req);
46
44
  if (!jwtToken) {
47
45
  const options = yield getAboutPageOptions(config);
48
- const html = (0, jsx_renderer_1.renderJSX)(views_1.AboutPage, options);
49
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
50
- return res.send(html);
46
+ return res.render('about', options);
51
47
  }
52
48
  else {
53
49
  next();
@@ -55,9 +51,7 @@ function handle(config) {
55
51
  }
56
52
  }
57
53
  const options = yield getAboutPageOptions(config);
58
- const html = (0, jsx_renderer_1.renderJSX)(views_1.AboutPage, options);
59
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
60
- return res.send(html);
54
+ return res.render('about', options);
61
55
  });
62
56
  }
63
57
  exports.default = handle;
@@ -8,11 +8,9 @@ const json_response_1 = __importDefault(require("../../middlewares/json-response
8
8
  const ui_module_1 = __importDefault(require("../../middlewares/ui-module"));
9
9
  const render_ui_module_1 = __importDefault(require("../../middlewares/render-ui-module"));
10
10
  const util_1 = require("../../util");
11
- const static_files_1 = require("../../util/static-files");
12
11
  const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client"));
13
12
  const compile_1 = __importDefault(require("./handlers/compile"));
14
13
  function register({ config, app }) {
15
- var _a;
16
14
  if (!config.aiPromptProvider) {
17
15
  return;
18
16
  }
@@ -23,8 +21,8 @@ function register({ config, app }) {
23
21
  moduleKey: config.aiPromptProvider.key,
24
22
  }), (0, compile_1.default)(config.aiPromptProvider));
25
23
  if (config.aiPromptProvider.formSchema || config.aiPromptProvider.uiPath) {
26
- app.use('/prompt-provider/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true, moduleType: config.aiPromptProvider.key }), (0, render_ui_module_1.default)(config.aiPromptProvider, config));
24
+ app.use('/prompt-provider/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true, moduleType: config.aiPromptProvider.key }), (0, render_ui_module_1.default)(config.aiPromptProvider));
27
25
  }
28
- app.get((0, util_1.getLogoUrl)(config.aiPromptProvider, '/ai-prompt-provider'), (0, static_files_1.serveFile)(config, ((_a = config.aiPromptProvider) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath));
26
+ app.get((0, util_1.getLogoUrl)(config.aiPromptProvider, '/ai-prompt-provider'), (req, res) => { var _a; return res.sendFile(((_a = config.aiPromptProvider) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath); });
29
27
  }
30
28
  exports.register = register;
@@ -10,17 +10,15 @@ const chat_completions_1 = __importDefault(require("./handlers/chat-completions"
10
10
  const ui_module_1 = __importDefault(require("../../middlewares/ui-module"));
11
11
  const render_ui_module_1 = __importDefault(require("../../middlewares/render-ui-module"));
12
12
  const util_1 = require("../../util");
13
- const static_files_1 = require("../../util/static-files");
14
13
  const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client"));
15
14
  function register({ config, app }) {
16
- var _a;
17
15
  if (!config.aiProvider) {
18
16
  return;
19
17
  }
20
18
  if (config.aiProvider.settingsUiModule) {
21
- app.use('/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true, moduleType: config.aiProvider.key }), (0, render_ui_module_1.default)(config.aiProvider.settingsUiModule, config));
19
+ app.use('/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true, moduleType: config.aiProvider.key }), (0, render_ui_module_1.default)(config.aiProvider.settingsUiModule));
22
20
  }
23
- app.get((0, util_1.getLogoUrl)(config.aiProvider, '/aiprovider'), (0, static_files_1.serveFile)(config, ((_a = config.aiProvider) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath));
21
+ app.get((0, util_1.getLogoUrl)(config.aiProvider, '/aiprovider'), (req, res) => { var _a; return res.sendFile(((_a = config.aiProvider) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath); });
24
22
  app.get('/ai-provider/models', json_response_1.default, (0, crowdin_client_1.default)({
25
23
  config,
26
24
  optional: false,
@@ -37,7 +37,7 @@ function registerAiToolWidgets({ config, app }) {
37
37
  const tools = Array.isArray(config.aiToolsWidget) ? config.aiToolsWidget : [config.aiToolsWidget];
38
38
  for (const tool of tools) {
39
39
  if ((0, util_1.isUniqueFunctionName)(tool)) {
40
- app.use((0, util_1.getAiToolWidgetUrl)(tool), (0, ui_module_1.default)({ config, moduleType: tool.key }), (0, render_ui_module_1.default)(tool, config));
40
+ app.use((0, util_1.getAiToolWidgetUrl)(tool), (0, ui_module_1.default)({ config, moduleType: tool.key }), (0, render_ui_module_1.default)(tool));
41
41
  }
42
42
  else {
43
43
  throw new Error(`The function name '${tool.function.name}' is not unique within aiTools and aiToolsWidget`);
@@ -16,14 +16,14 @@ function register({ config, app }) {
16
16
  if (Array.isArray(config.contextMenu)) {
17
17
  config.contextMenu.forEach((contextMenu) => {
18
18
  if ((contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.uiPath) || (contextMenu === null || contextMenu === void 0 ? void 0 : contextMenu.formSchema)) {
19
- app.use(`/context-${contextMenu.key}`, (0, ui_module_1.default)({ config, allowUnauthorized, moduleType: contextMenu.key }), (0, render_ui_module_1.default)(contextMenu, config));
19
+ app.use(`/context-${contextMenu.key}`, (0, ui_module_1.default)({ config, allowUnauthorized, moduleType: contextMenu.key }), (0, render_ui_module_1.default)(contextMenu));
20
20
  }
21
21
  });
22
22
  }
23
23
  else {
24
24
  // backward compatibility will be removed after migration
25
25
  if (((_a = config.contextMenu) === null || _a === void 0 ? void 0 : _a.uiPath) || ((_b = config.contextMenu) === null || _b === void 0 ? void 0 : _b.formSchema)) {
26
- app.use('/context', (0, ui_module_1.default)({ config, allowUnauthorized, moduleType: config.contextMenu.key }), (0, render_ui_module_1.default)(config.contextMenu, config));
26
+ app.use('/context', (0, ui_module_1.default)({ config, allowUnauthorized, moduleType: config.contextMenu.key }), (0, render_ui_module_1.default)(config.contextMenu));
27
27
  }
28
28
  }
29
29
  }
@@ -6,14 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.register = void 0;
7
7
  const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client"));
8
8
  const util_1 = require("../../util");
9
- const static_files_1 = require("../../util/static-files");
10
9
  const translate_1 = __importDefault(require("./handlers/translate"));
11
10
  function register({ config, app }) {
12
- var _a;
13
11
  if (!config.customMT) {
14
12
  return;
15
13
  }
16
- app.get((0, util_1.getLogoUrl)(config.customMT, '/mt'), (0, static_files_1.serveFile)(config, ((_a = config.customMT) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath));
14
+ app.get((0, util_1.getLogoUrl)(config.customMT, '/mt'), (req, res) => { var _a; return res.sendFile(((_a = config.customMT) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath); });
17
15
  app.post('/mt/translate', (0, crowdin_client_1.default)({
18
16
  config,
19
17
  optional: false,
@@ -17,9 +17,9 @@ function register({ config, app }) {
17
17
  }
18
18
  if ((0, util_1.isAuthorizedConfig)(config)) {
19
19
  if (config.customSpellchecker.settingsUiModule) {
20
- app.use('/spellchecker/settings', (0, ui_module_1.default)({ config, moduleType: config.customSpellchecker.key }), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule, config));
20
+ app.use('/spellchecker/settings', (0, ui_module_1.default)({ config, moduleType: config.customSpellchecker.key }), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule));
21
21
  // TEMPORARY CODE: it needs to support old path
22
- app.use('/settings', (0, ui_module_1.default)({ config }), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule, config));
22
+ app.use('/settings', (0, ui_module_1.default)({ config }), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule));
23
23
  // END TEMPORARY CODE
24
24
  }
25
25
  app.get('/spellchecker/languages', json_response_1.default, (0, crowdin_client_1.default)({
@@ -49,9 +49,9 @@ function register({ config, app }) {
49
49
  return;
50
50
  }
51
51
  if (config.customSpellchecker.settingsUiModule) {
52
- app.use('/spellchecker/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true, moduleType: config.customSpellchecker.key }), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule, config));
52
+ app.use('/spellchecker/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true, moduleType: config.customSpellchecker.key }), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule));
53
53
  // TEMPORARY CODE: it needs to support old path
54
- app.use('/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true }), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule, config));
54
+ app.use('/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true }), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule));
55
55
  // END TEMPORARY CODE
56
56
  }
57
57
  app.get('/spellchecker/languages', json_response_1.default, (0, get_languages_list_1.default)(config.customSpellchecker));
@@ -12,6 +12,6 @@ function register({ config, app }) {
12
12
  return;
13
13
  }
14
14
  const allowUnauthorized = !(0, util_1.isAuthorizedConfig)(config);
15
- app.use('/editor-panels', (0, ui_module_1.default)({ config, allowUnauthorized, moduleType: config.editorRightPanel.key }), (0, render_ui_module_1.default)(config.editorRightPanel, config));
15
+ app.use('/editor-panels', (0, ui_module_1.default)({ config, allowUnauthorized, moduleType: config.editorRightPanel.key }), (0, render_ui_module_1.default)(config.editorRightPanel));
16
16
  }
17
17
  exports.register = register;
@@ -38,9 +38,9 @@ function register({ config, app }) {
38
38
  }), (0, validate_1.default)(qaCheck));
39
39
  // END TEMPORARY CODE
40
40
  if (qaCheck.settingsUiModule) {
41
- app.use('/qa-check/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true, moduleType: qaCheck.key }), (0, render_ui_module_1.default)(qaCheck.settingsUiModule, config));
41
+ app.use('/qa-check/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true, moduleType: qaCheck.key }), (0, render_ui_module_1.default)(qaCheck.settingsUiModule));
42
42
  // TEMPORARY CODE: it needs to support old path
43
- app.use('/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true }), (0, render_ui_module_1.default)(qaCheck.settingsUiModule, config));
43
+ app.use('/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true }), (0, render_ui_module_1.default)(qaCheck.settingsUiModule));
44
44
  // END TEMPORARY CODE
45
45
  }
46
46
  }
@@ -15,16 +15,18 @@ const logger_1 = require("../../../util/logger");
15
15
  const files_1 = require("../util/files");
16
16
  function handle(config, integration) {
17
17
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
18
- req.logInfo('Loading crowdin files');
18
+ var _a;
19
+ const mode = (_a = req.query) === null || _a === void 0 ? void 0 : _a.mode;
20
+ req.logInfo(`Loading crowdin files${mode ? ` (mode: ${mode})` : ''}`);
19
21
  if (integration.getCrowdinFiles) {
20
22
  const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, req.crowdinApiClient, req.crowdinContext.jwtPayload.context.project_id);
21
23
  req.logInfo(`Loading files ${rootFolder ? `from folder ${rootFolder.id}` : 'from root'}`);
22
24
  try {
23
25
  let files = integration.getCrowdinFiles
24
- ? yield integration.getCrowdinFiles(req.crowdinContext.jwtPayload.context.project_id, req.crowdinApiClient, rootFolder, req.integrationSettings)
26
+ ? yield integration.getCrowdinFiles(req.crowdinContext.jwtPayload.context.project_id, req.crowdinApiClient, rootFolder, req.integrationSettings, mode)
25
27
  : [];
26
28
  req.logInfo('Marking files as unsynced');
27
- if (files.length > 0) {
29
+ if (files.length > 0 && mode !== 'directories') {
28
30
  files = yield (0, files_1.markUnsyncedFiles)({
29
31
  integrationId: req.crowdinContext.clientId,
30
32
  crowdinId: req.crowdinContext.crowdinId,
@@ -32,7 +34,7 @@ function handle(config, integration) {
32
34
  files,
33
35
  });
34
36
  }
35
- req.logInfo(`Returning ${files.length} files`);
37
+ req.logInfo(`Returning ${files.length} items`);
36
38
  res.send(files);
37
39
  }
38
40
  catch (e) {
@@ -22,9 +22,10 @@ const files_1 = require("../util/files");
22
22
  const types_2 = require("../types");
23
23
  function handle(config, integration) {
24
24
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
25
- var _a, _b, _c;
25
+ var _a, _b, _c, _d;
26
26
  const projectId = req.crowdinContext.jwtPayload.context.project_id || (req === null || req === void 0 ? void 0 : req.body.projectId);
27
27
  const uploadTranslations = req.query.uploadTranslations === 'true' || ((_a = req.body) === null || _a === void 0 ? void 0 : _a.uploadTranslations);
28
+ const forcePushSources = req.query.forcePushSources === 'true' || ((_b = req.body) === null || _b === void 0 ? void 0 : _b.forcePushSources);
28
29
  req.logInfo(`Updating crowdin project ${projectId}`);
29
30
  const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, req.crowdinApiClient, projectId);
30
31
  if (rootFolder) {
@@ -38,14 +39,14 @@ function handle(config, integration) {
38
39
  });
39
40
  }
40
41
  // A request via API has a different structure
41
- if (((_b = config.api) === null || _b === void 0 ? void 0 : _b.default) && req.body.files) {
42
+ if (((_c = config.api) === null || _c === void 0 ? void 0 : _c.default) && req.body.files) {
42
43
  req.body = req.body.files;
43
44
  }
44
45
  let payload = req.body;
45
46
  const excludedTargetLanguages = yield (0, files_1.getExcludedTargetLanguages)({
46
47
  client: req.crowdinApiClient,
47
48
  projectId,
48
- languages: ((_c = req.query.languages) === null || _c === void 0 ? void 0 : _c.split(',')) || [],
49
+ languages: ((_d = req.query.languages) === null || _d === void 0 ? void 0 : _d.split(',')) || [],
49
50
  });
50
51
  yield (0, job_1.runAsJob)({
51
52
  integrationId: req.crowdinContext.clientId,
@@ -63,6 +64,9 @@ function handle(config, integration) {
63
64
  payload = yield (0, files_1.expandFilesTree)(payload, req, integration, job);
64
65
  payload = (0, lodash_uniqby_1.default)(payload, 'id');
65
66
  }
67
+ if (!forcePushSources && (payload === null || payload === void 0 ? void 0 : payload.length)) {
68
+ payload = yield (0, files_1.filterSyncedData)(payload);
69
+ }
66
70
  const result = yield integration.updateCrowdin({
67
71
  projectId,
68
72
  client: req.crowdinApiClient,
@@ -97,7 +101,17 @@ function handle(config, integration) {
97
101
  }
98
102
  return { message };
99
103
  }),
100
- onError: (e) => __awaiter(this, void 0, void 0, function* () {
104
+ onError: (e, job) => __awaiter(this, void 0, void 0, function* () {
105
+ try {
106
+ const currentJob = yield job.get();
107
+ if (currentJob === null || currentJob === void 0 ? void 0 : currentJob.processedEntities) {
108
+ const processedEntities = JSON.parse(currentJob.processedEntities);
109
+ yield (0, files_1.updateSyncedData)(req.crowdinContext.clientId, req.crowdinContext.crowdinId, processedEntities, types_2.Provider.INTEGRATION);
110
+ }
111
+ }
112
+ catch (syncError) {
113
+ (0, logger_1.logError)(syncError, req.crowdinContext);
114
+ }
101
115
  yield (0, logger_1.handleUserError)({
102
116
  action: 'Sync files to Crowdin',
103
117
  error: e,
@@ -43,9 +43,11 @@ function handle(integration) {
43
43
  const excludePatterns = (_c = appSettings === null || appSettings === void 0 ? void 0 : appSettings.excludeByFilePath) === null || _c === void 0 ? void 0 : _c.split('\n').filter(Boolean);
44
44
  files = (0, files_1.filterFilesByPath)(files, includePatterns, excludePatterns);
45
45
  }
46
- if (((_e = (_d = integration.filtering) === null || _d === void 0 ? void 0 : _d.integrationFileStatus) === null || _e === void 0 ? void 0 : _e.isNew) ||
46
+ const needsFileStatus = ((_e = (_d = integration.filtering) === null || _d === void 0 ? void 0 : _d.integrationFileStatus) === null || _e === void 0 ? void 0 : _e.isNew) ||
47
47
  ((_g = (_f = integration.filtering) === null || _f === void 0 ? void 0 : _f.integrationFileStatus) === null || _g === void 0 ? void 0 : _g.isUpdated) ||
48
- ((_j = (_h = integration.filtering) === null || _h === void 0 ? void 0 : _h.integrationFileStatus) === null || _j === void 0 ? void 0 : _j.notSynced)) {
48
+ ((_j = (_h = integration.filtering) === null || _h === void 0 ? void 0 : _h.integrationFileStatus) === null || _j === void 0 ? void 0 : _j.notSynced) ||
49
+ integration.forcePushSources === true;
50
+ if (needsFileStatus) {
49
51
  const syncedData = yield (0, storage_1.getStorage)().getSyncedData(clientId, crowdinId, types_1.Provider.INTEGRATION);
50
52
  const syncedFiles = (syncedData === null || syncedData === void 0 ? void 0 : syncedData.files) ? JSON.parse(syncedData.files) : [];
51
53
  const lastSyncTimestamp = (syncedData === null || syncedData === void 0 ? void 0 : syncedData.updatedAt) ? Number(syncedData.updatedAt) : null;
@@ -54,23 +56,25 @@ function handle(integration) {
54
56
  if (!file.type) {
55
57
  return file;
56
58
  }
57
- const notSynced = ((_b = (_a = integration.filtering) === null || _a === void 0 ? void 0 : _a.integrationFileStatus) === null || _b === void 0 ? void 0 : _b.notSynced) === true
58
- ? !syncedFiles.some((syncedItem) => syncedItem.id === file.id)
59
- : false;
59
+ const syncedFile = syncedFiles.find((syncedItem) => syncedItem.id === file.id);
60
+ const notSynced = ((_b = (_a = integration.filtering) === null || _a === void 0 ? void 0 : _a.integrationFileStatus) === null || _b === void 0 ? void 0 : _b.notSynced) === true ? !syncedFile : false;
61
+ const fileSyncTimestamp = (syncedFile === null || syncedFile === void 0 ? void 0 : syncedFile.syncedAt) ? Number(syncedFile.syncedAt) : lastSyncTimestamp;
60
62
  const isNew = ((_d = (_c = integration.filtering) === null || _c === void 0 ? void 0 : _c.integrationFileStatus) === null || _d === void 0 ? void 0 : _d.isNew) === true
61
- ? !syncedFiles.some((syncedItem) => syncedItem.id === file.id) &&
62
- lastSyncTimestamp &&
63
+ ? !syncedFile &&
64
+ fileSyncTimestamp &&
63
65
  file.createdAt &&
64
66
  (typeof file.createdAt === 'string'
65
67
  ? new Date(file.createdAt).getTime()
66
- : file.createdAt) > Number(lastSyncTimestamp)
68
+ : file.createdAt) > fileSyncTimestamp
67
69
  : false;
68
- const isUpdated = ((_f = (_e = integration.filtering) === null || _e === void 0 ? void 0 : _e.integrationFileStatus) === null || _f === void 0 ? void 0 : _f.isUpdated) === true
69
- ? lastSyncTimestamp &&
70
+ const shouldCalculateIsUpdated = ((_f = (_e = integration.filtering) === null || _e === void 0 ? void 0 : _e.integrationFileStatus) === null || _f === void 0 ? void 0 : _f.isUpdated) === true ||
71
+ integration.forcePushSources === true;
72
+ const isUpdated = shouldCalculateIsUpdated
73
+ ? syncedFile &&
74
+ fileSyncTimestamp &&
70
75
  file.updatedAt &&
71
- (typeof file.updatedAt === 'string'
72
- ? new Date(file.updatedAt).getTime()
73
- : file.updatedAt) > Number(lastSyncTimestamp)
76
+ (typeof file.updatedAt === 'string' ? new Date(file.updatedAt).getTime() : file.updatedAt) >
77
+ fileSyncTimestamp
74
78
  : false;
75
79
  return Object.assign(Object.assign({}, file), { isNew,
76
80
  notSynced,
@@ -14,7 +14,6 @@ const logger_1 = require("../../../util/logger");
14
14
  const subscription_1 = require("../../../util/subscription");
15
15
  const defaults_1 = require("../util/defaults");
16
16
  const users_1 = require("./users");
17
- const views_1 = require("../../../views");
18
17
  function handle(config, integration) {
19
18
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
20
19
  var _a, _b, _c, _d;
@@ -78,9 +77,11 @@ function handle(config, integration) {
78
77
  : {};
79
78
  options.integrationOneLevelFetching = integration.integrationOneLevelFetching;
80
79
  options.integrationSearchListener = integration.integrationSearchListener;
80
+ options.progressiveCrowdinFilesLoading = integration.progressiveCrowdinFilesLoading;
81
81
  options.checkSubscription = !(0, subscription_1.isAppFree)(config);
82
82
  options.uploadTranslations = integration.uploadTranslations;
83
83
  options.forcePushTranslations = integration.forcePushTranslations;
84
+ options.forcePushSources = integration.forcePushSources;
84
85
  options.excludedTargetLanguages = integration.excludedTargetLanguages;
85
86
  options.sentryData = process.env.SENTRY_DSN
86
87
  ? {
@@ -93,18 +94,7 @@ function handle(config, integration) {
93
94
  checkInterval: ((_d = integration.asyncProgress) === null || _d === void 0 ? void 0 : _d.checkInterval) || 1000,
94
95
  };
95
96
  logger(`Routing user to ${view} view`);
96
- let html;
97
- if (view === 'install') {
98
- html = (0, util_1.renderJSX)(views_1.InstallPage, options);
99
- }
100
- else if (view === 'login') {
101
- html = (0, util_1.renderJSX)(views_1.LoginPage, options);
102
- }
103
- else {
104
- html = (0, util_1.renderJSX)(views_1.MainPage, options);
105
- }
106
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
107
- return res.send(html);
97
+ return res.render(view, options);
108
98
  }));
109
99
  }
110
100
  exports.default = handle;
@@ -18,7 +18,6 @@ const defaults_1 = require("../util/defaults");
18
18
  const logger_1 = require("../../../util/logger");
19
19
  const storage_1 = require("../../../storage");
20
20
  const crowdin_apps_functions_1 = require("@crowdin/crowdin-apps-functions");
21
- const views_1 = require("../../../views");
22
21
  function handle(config, integration) {
23
22
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
24
23
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
@@ -66,19 +65,12 @@ function handle(config, integration) {
66
65
  yield (0, storage_1.getStorage)().deleteMetadata((0, defaults_1.getOAuthPollingId)(clientId));
67
66
  yield (0, storage_1.getStorage)().saveMetadata((0, defaults_1.getOAuthPollingId)(clientId), oauthCredentials, organization);
68
67
  }
69
- const html = (0, util_1.renderJSX)(views_1.OAuthPage, {
70
- message: JSON.stringify(message),
71
- oauthMode: (_p = integration.oauthLogin) === null || _p === void 0 ? void 0 : _p.mode,
72
- });
73
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
74
- return res.send(html);
68
+ return res.render('oauth', { message: JSON.stringify(message), oauthMode: (_p = integration.oauthLogin) === null || _p === void 0 ? void 0 : _p.mode });
75
69
  }
76
70
  catch (e) {
77
71
  (0, logger_1.logError)(e);
78
72
  message.data = { error: (0, logger_1.getErrorMessage)(e) };
79
- const html = (0, util_1.renderJSX)(views_1.OAuthPage, { message: JSON.stringify(message) });
80
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
81
- return res.send(html);
73
+ return res.render('oauth', { message: JSON.stringify(message) });
82
74
  }
83
75
  }));
84
76
  }
@@ -36,11 +36,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
38
  exports.register = void 0;
39
+ const cron = __importStar(require("node-cron"));
39
40
  const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client"));
40
41
  const integration_credentials_1 = __importDefault(require("../../middlewares/integration-credentials"));
41
42
  const json_response_1 = __importDefault(require("../../middlewares/json-response"));
42
43
  const util_1 = require("../../util");
43
- const static_files_1 = require("../../util/static-files");
44
44
  const defaults_1 = require("./util/defaults");
45
45
  const webhooks_1 = require("./util/webhooks");
46
46
  const crowdin_file_progress_1 = __importDefault(require("./handlers/crowdin-file-progress"));
@@ -75,7 +75,7 @@ function register({ config, app }) {
75
75
  return;
76
76
  }
77
77
  (0, defaults_1.applyIntegrationModuleDefaults)(config, integrationLogic);
78
- app.get((0, util_1.getLogoUrl)(integrationLogic, '/integration'), (0, static_files_1.serveFile)(config, integrationLogic.imagePath || config.imagePath));
78
+ app.get((0, util_1.getLogoUrl)(integrationLogic, '/integration'), (req, res) => res.sendFile(integrationLogic.imagePath || config.imagePath));
79
79
  app.get('/', (0, crowdin_client_1.default)({
80
80
  config,
81
81
  optional: true,
@@ -183,32 +183,25 @@ function register({ config, app }) {
183
183
  }), (0, oauth_polling_1.default)(integrationLogic));
184
184
  }
185
185
  }
186
- Promise.resolve().then(() => __importStar(require('node-cron'))).then((nodeCron) => {
187
- const cron = nodeCron.default || nodeCron;
188
- if (integrationLogic.cronJobs) {
189
- integrationLogic.cronJobs.forEach((job) => {
190
- cron.schedule(job.expression, () => (0, cron_1.runJob)({ config, integration: integrationLogic, job }).catch(console.error));
191
- });
192
- }
193
- if (integrationLogic.withCronSync) {
194
- cron.schedule('0 * * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '1' }).catch(console.error));
195
- cron.schedule('0 */3 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '3' }).catch(console.error));
196
- cron.schedule('0 */6 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '6' }).catch(console.error));
197
- cron.schedule('0 */12 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '12' }).catch(console.error));
198
- cron.schedule('0 0 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '24' }).catch(console.error));
186
+ if (integrationLogic.cronJobs) {
187
+ integrationLogic.cronJobs.forEach((job) => {
188
+ cron.schedule(job.expression, () => (0, cron_1.runJob)({ config, integration: integrationLogic, job }).catch(console.error));
189
+ });
190
+ }
191
+ if (integrationLogic.withCronSync) {
192
+ cron.schedule('0 * * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '1' }).catch(console.error));
193
+ cron.schedule('0 */3 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '3' }).catch(console.error));
194
+ cron.schedule('0 */6 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '6' }).catch(console.error));
195
+ cron.schedule('0 */12 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '12' }).catch(console.error));
196
+ cron.schedule('0 0 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '24' }).catch(console.error));
197
+ }
198
+ // remove user errors
199
+ cron.schedule('0 0 * * *', () => __awaiter(this, void 0, void 0, function* () {
200
+ if (integrationLogic.userErrorLifetimeDays) {
201
+ const date = (0, util_1.getPreviousDate)(integrationLogic.userErrorLifetimeDays);
202
+ yield (0, storage_1.getStorage)().deleteAllUsersErrorsOlderThan(`${date.getTime()}`);
199
203
  }
200
- // remove user errors
201
- cron.schedule('0 0 * * *', () => __awaiter(this, void 0, void 0, function* () {
202
- if (integrationLogic.userErrorLifetimeDays) {
203
- const date = (0, util_1.getPreviousDate)(integrationLogic.userErrorLifetimeDays);
204
- yield (0, storage_1.getStorage)().deleteAllUsersErrorsOlderThan(`${date.getTime()}`);
205
- }
206
- }));
207
- cron.schedule('0 0 1 * *', () => (0, cron_1.removeFinishedJobs)());
208
- })
209
- .catch(() => {
210
- // node-cron not available (e.g., Cloudflare Workers)
211
- });
204
+ }));
212
205
  if (integrationLogic.webhooks) {
213
206
  app.post(`${integrationLogic.webhooks.crowdinWebhookUrl
214
207
  ? integrationLogic.webhooks.crowdinWebhookUrl
@@ -245,5 +238,6 @@ function register({ config, app }) {
245
238
  checkSubscriptionExpiration: true,
246
239
  moduleKey: integrationLogic.key,
247
240
  }), (0, integration_credentials_1.default)(config, integrationLogic), (0, invite_users_1.default)());
241
+ cron.schedule('0 0 1 * *', () => (0, cron_1.removeFinishedJobs)());
248
242
  }
249
243
  exports.register = register;