@crowdin/app-project-module 0.105.1 → 0.107.0-cf-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 (164) hide show
  1. package/out/app-test/integration/get-integration-files.js +0 -1
  2. package/out/app-test/integration/mocks/mock-axios.js +0 -1
  3. package/out/app-test/integration/update-crowdin.js +0 -1
  4. package/out/app-test/integration/update-integration.js +0 -1
  5. package/out/index.d.ts +1 -0
  6. package/out/index.js +30 -12
  7. package/out/middlewares/crowdin-client.d.ts +1 -1
  8. package/out/middlewares/integration-credentials.d.ts +1 -1
  9. package/out/middlewares/integration-credentials.js +4 -1
  10. package/out/middlewares/render-ui-module.d.ts +3 -3
  11. package/out/middlewares/render-ui-module.js +9 -13
  12. package/out/middlewares/ui-module.d.ts +1 -1
  13. package/out/middlewares/ui-module.js +10 -1
  14. package/out/modules/about.d.ts +2 -1
  15. package/out/modules/about.js +10 -3
  16. package/out/modules/ai-prompt-provider/handlers/compile.d.ts +1 -1
  17. package/out/modules/ai-prompt-provider/index.js +2 -2
  18. package/out/modules/ai-provider/handlers/chat-completions.d.ts +1 -1
  19. package/out/modules/ai-provider/handlers/chat-completions.js +0 -1
  20. package/out/modules/ai-provider/handlers/get-model-list.d.ts +1 -1
  21. package/out/modules/ai-provider/index.js +2 -2
  22. package/out/modules/ai-provider/types.d.ts +2 -2
  23. package/out/modules/ai-provider/util/index.js +0 -2
  24. package/out/modules/ai-request-processors/handler.d.ts +1 -1
  25. package/out/modules/ai-tools/handlers/tool-calls.d.ts +1 -1
  26. package/out/modules/ai-tools/index.js +1 -1
  27. package/out/modules/api/api.js +0 -1
  28. package/out/modules/auth-guard/handlers/verify.d.ts +1 -1
  29. package/out/modules/auth-guard/index.js +1 -1
  30. package/out/modules/automation-action/handlers/execute.d.ts +1 -1
  31. package/out/modules/automation-action/handlers/input-schema.d.ts +1 -1
  32. package/out/modules/automation-action/handlers/output-schema.d.ts +1 -1
  33. package/out/modules/automation-action/handlers/validate-settings.d.ts +1 -1
  34. package/out/modules/automation-action/index.js +1 -1
  35. package/out/modules/context-menu/index.js +2 -2
  36. package/out/modules/custom-mt/handlers/translate.d.ts +2 -2
  37. package/out/modules/custom-mt/handlers/translate.js +53 -4
  38. package/out/modules/custom-mt/index.js +6 -3
  39. package/out/modules/custom-mt/types.d.ts +14 -2
  40. package/out/modules/custom-spell-check/handlers/get-languages-list.d.ts +1 -1
  41. package/out/modules/custom-spell-check/handlers/spell-check.d.ts +1 -1
  42. package/out/modules/custom-spell-check/index.js +4 -4
  43. package/out/modules/editor-right-panel/index.js +1 -1
  44. package/out/modules/external-qa-check/handlers/validate.d.ts +1 -1
  45. package/out/modules/external-qa-check/index.js +2 -2
  46. package/out/modules/file-processing/handlers/custom-file-format.d.ts +7 -2
  47. package/out/modules/file-processing/handlers/custom-file-format.js +59 -19
  48. package/out/modules/file-processing/handlers/file-download.d.ts +1 -1
  49. package/out/modules/file-processing/handlers/file-download.js +5 -0
  50. package/out/modules/file-processing/handlers/pre-post-process.d.ts +1 -1
  51. package/out/modules/file-processing/handlers/pre-post-process.js +34 -14
  52. package/out/modules/file-processing/handlers/translations-alignment.d.ts +1 -1
  53. package/out/modules/file-processing/index.js +12 -2
  54. package/out/modules/file-processing/util/defaults.js +50 -6
  55. package/out/modules/file-processing/util/files.js +2 -1
  56. package/out/modules/form-data-display.d.ts +1 -1
  57. package/out/modules/form-data-save.d.ts +1 -1
  58. package/out/modules/install.d.ts +1 -1
  59. package/out/modules/integration/handlers/crowdin-file-progress.d.ts +1 -1
  60. package/out/modules/integration/handlers/crowdin-files.d.ts +1 -1
  61. package/out/modules/integration/handlers/crowdin-project.d.ts +1 -1
  62. package/out/modules/integration/handlers/crowdin-update.d.ts +1 -1
  63. package/out/modules/integration/handlers/crowdin-webhook.d.ts +1 -1
  64. package/out/modules/integration/handlers/integration-data.d.ts +1 -1
  65. package/out/modules/integration/handlers/integration-login.d.ts +1 -1
  66. package/out/modules/integration/handlers/integration-logout.d.ts +1 -1
  67. package/out/modules/integration/handlers/integration-update.d.ts +1 -1
  68. package/out/modules/integration/handlers/integration-webhook.d.ts +1 -1
  69. package/out/modules/integration/handlers/invite-users.d.ts +1 -1
  70. package/out/modules/integration/handlers/job-cancel.d.ts +1 -1
  71. package/out/modules/integration/handlers/job-info-deprecated.d.ts +1 -1
  72. package/out/modules/integration/handlers/job-info.d.ts +1 -1
  73. package/out/modules/integration/handlers/job-list.d.ts +1 -1
  74. package/out/modules/integration/handlers/main.d.ts +1 -1
  75. package/out/modules/integration/handlers/main.js +13 -1
  76. package/out/modules/integration/handlers/oauth-login.d.ts +1 -1
  77. package/out/modules/integration/handlers/oauth-login.js +12 -3
  78. package/out/modules/integration/handlers/oauth-polling.d.ts +2 -2
  79. package/out/modules/integration/handlers/oauth-polling.js +5 -3
  80. package/out/modules/integration/handlers/oauth-url.d.ts +1 -1
  81. package/out/modules/integration/handlers/settings-save.d.ts +1 -1
  82. package/out/modules/integration/handlers/settings.d.ts +1 -1
  83. package/out/modules/integration/handlers/sync-settings-save.d.ts +1 -1
  84. package/out/modules/integration/handlers/sync-settings-save.js +0 -2
  85. package/out/modules/integration/handlers/sync-settings.d.ts +1 -1
  86. package/out/modules/integration/handlers/user-errors.d.ts +1 -1
  87. package/out/modules/integration/handlers/users.d.ts +1 -1
  88. package/out/modules/integration/index.js +13 -34
  89. package/out/modules/integration/util/cron.js +1 -10
  90. package/out/modules/integration/util/defaults.js +31 -28
  91. package/out/modules/integration/util/files.js +18 -11
  92. package/out/modules/integration/util/job.js +0 -4
  93. package/out/modules/integration/util/snapshot.js +1 -5
  94. package/out/modules/integration/util/webhooks.js +1 -8
  95. package/out/modules/manifest.js +15 -13
  96. package/out/modules/modal/index.js +2 -2
  97. package/out/modules/organization-menu/index.js +5 -4
  98. package/out/modules/organization-settings-menu/index.js +5 -4
  99. package/out/modules/profile-resources-menu/index.js +5 -4
  100. package/out/modules/profile-settings-menu/index.js +5 -4
  101. package/out/modules/project-menu/index.js +1 -1
  102. package/out/modules/project-menu-crowdsource/index.js +1 -1
  103. package/out/modules/project-reports/index.js +3 -2
  104. package/out/modules/project-tools/index.js +3 -2
  105. package/out/modules/status.d.ts +1 -1
  106. package/out/modules/status.js +12 -3
  107. package/out/modules/subscription-paid.d.ts +1 -1
  108. package/out/modules/uninstall.d.ts +1 -1
  109. package/out/modules/webhooks/handlers/webhook-handler.d.ts +1 -1
  110. package/out/modules/webhooks/handlers/webhook-handler.js +30 -15
  111. package/out/modules/webhooks/types.d.ts +7 -0
  112. package/out/modules/workflow-step-type/handlers/delete-step.d.ts +1 -1
  113. package/out/modules/workflow-step-type/handlers/step-settings-save.d.ts +1 -1
  114. package/out/modules/workflow-step-type/index.js +2 -2
  115. package/out/storage/d1.d.ts +107 -0
  116. package/out/storage/d1.js +829 -0
  117. package/out/storage/index.js +8 -2
  118. package/out/storage/mysql.js +0 -3
  119. package/out/storage/postgre.js +0 -1
  120. package/out/storage/sqlite.js +0 -3
  121. package/out/types.d.ts +41 -2
  122. package/out/util/axios.js +0 -1
  123. package/out/util/credentials-masker.d.ts +1 -1
  124. package/out/util/cron.d.ts +29 -0
  125. package/out/util/cron.js +87 -0
  126. package/out/util/index.d.ts +12 -1
  127. package/out/util/index.js +54 -6
  128. package/out/util/jsx-renderer.d.ts +6 -0
  129. package/out/util/jsx-renderer.js +13 -0
  130. package/out/util/logger.js +0 -4
  131. package/out/util/static-files.d.ts +19 -0
  132. package/out/util/static-files.js +87 -0
  133. package/out/views/AboutPage.d.ts +10 -0
  134. package/out/views/AboutPage.js +76 -0
  135. package/out/views/ErrorPage.d.ts +18 -0
  136. package/out/views/ErrorPage.js +56 -0
  137. package/out/views/FormPage.d.ts +14 -0
  138. package/out/views/FormPage.js +28 -0
  139. package/out/views/InstallPage.d.ts +10 -0
  140. package/out/views/InstallPage.js +22 -0
  141. package/out/views/LoginPage.d.ts +33 -0
  142. package/out/views/LoginPage.js +200 -0
  143. package/out/views/MainPage.d.ts +81 -0
  144. package/out/views/MainPage.js +1784 -0
  145. package/out/views/OAuthPage.d.ts +7 -0
  146. package/out/views/OAuthPage.js +17 -0
  147. package/out/views/SubscriptionPage.d.ts +7 -0
  148. package/out/views/SubscriptionPage.js +26 -0
  149. package/out/views/index.d.ts +13 -0
  150. package/out/views/index.js +25 -0
  151. package/out/views/layout/Head.d.ts +9 -0
  152. package/out/views/layout/Head.js +54 -0
  153. package/package.json +33 -18
  154. package/out/util/handlebars.d.ts +0 -1
  155. package/out/util/handlebars.js +0 -46
  156. package/out/views/about.handlebars +0 -102
  157. package/out/views/error.handlebars +0 -54
  158. package/out/views/form.handlebars +0 -31
  159. package/out/views/install.handlebars +0 -16
  160. package/out/views/login.handlebars +0 -332
  161. package/out/views/main.handlebars +0 -2042
  162. package/out/views/oauth.handlebars +0 -11
  163. package/out/views/partials/head.handlebars +0 -53
  164. package/out/views/subscription.handlebars +0 -26
@@ -8,10 +8,24 @@ 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 fs_1 = __importDefault(require("fs"));
16
+ const path_1 = __importDefault(require("path"));
12
17
  const util_1 = require("../../../util");
13
18
  const logger_1 = require("../../../util/logger");
14
- function handle(config) {
19
+ const files_1 = require("../../file-processing/util/files");
20
+ function handle({ baseUrl, folder, config, fileStore }) {
21
+ let dataFolder = '';
22
+ if (!fileStore) {
23
+ dataFolder = path_1.default.join(folder, 'custom-mt');
24
+ if (!fs_1.default.existsSync(dataFolder)) {
25
+ fs_1.default.mkdirSync(dataFolder, { recursive: true });
26
+ }
27
+ }
28
+ const baseFilesUrl = `${baseUrl}/file/download/custom-mt`;
15
29
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
30
  const source = req.query.source;
17
31
  const target = req.query.target;
@@ -21,7 +35,17 @@ function handle(config) {
21
35
  (0, logger_1.log)(`Payload ${JSON.stringify(body, null, 2)}`);
22
36
  const projectId = req.query.project_id ? Number(req.query.project_id) : null;
23
37
  try {
24
- const isValidationRequest = source === 'en' && target === 'de' && body.strings && body.strings[0] === 'validation';
38
+ let strings;
39
+ if (body.strings) {
40
+ strings = body.strings;
41
+ }
42
+ else if (body.stringsUrl) {
43
+ strings = (yield (0, files_1.getFileStrings)(body.stringsUrl));
44
+ }
45
+ else {
46
+ throw new Error('Bad payload received: No strings found');
47
+ }
48
+ const isValidationRequest = source === 'en' && target === 'de' && strings.length > 0 && strings[0] === 'validation';
25
49
  if (isValidationRequest) {
26
50
  if (config.validate) {
27
51
  yield config.validate(req.crowdinApiClient);
@@ -29,8 +53,33 @@ function handle(config) {
29
53
  res.send({ data: { translations: [] } });
30
54
  return;
31
55
  }
32
- const translations = yield config.translate(req.crowdinApiClient, req.crowdinContext, projectId, source, target, body.strings);
33
- res.send({ data: { translations } });
56
+ const translations = yield config.translate(req.crowdinApiClient, req.crowdinContext, projectId, source, target, strings);
57
+ if (!Array.isArray(translations)) {
58
+ res.send({ data: { translations } });
59
+ return;
60
+ }
61
+ const translationsNDJson = translations.map((t) => JSON.stringify(t)).join('\n');
62
+ const bufferData = Buffer.from(translationsNDJson, 'utf8');
63
+ if (Buffer.byteLength(bufferData) < files_1.MAX_BODY_SIZE) {
64
+ res.send({ data: { translations } });
65
+ }
66
+ else {
67
+ let url;
68
+ if (fileStore) {
69
+ const fileRef = yield fileStore.storeFile(bufferData);
70
+ url = `${baseFilesUrl}?file=${fileRef}`;
71
+ }
72
+ else {
73
+ if (config.storeFile) {
74
+ url = yield config.storeFile(bufferData);
75
+ }
76
+ else {
77
+ const storedFile = yield (0, files_1.storeFile)(bufferData, dataFolder);
78
+ url = `${baseFilesUrl}?file=${storedFile}`;
79
+ }
80
+ }
81
+ res.send({ data: { translationsUrl: url } });
82
+ }
34
83
  }
35
84
  catch (e) {
36
85
  req.logError(e);
@@ -6,24 +6,27 @@ 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 file_download_1 = __importDefault(require("../file-processing/handlers/file-download"));
9
10
  const translate_1 = __importDefault(require("./handlers/translate"));
10
11
  function register({ config, app }) {
11
12
  if (!config.customMT) {
12
13
  return;
13
14
  }
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); });
15
+ const folder = config.customMT.filesFolder || config.dbFolder;
16
+ app.use('/logo/mt', (0, util_1.serveLogo)(config, config.customMT));
15
17
  app.post('/mt/translate', (0, crowdin_client_1.default)({
16
18
  config,
17
19
  optional: false,
18
20
  checkSubscriptionExpiration: true,
19
21
  moduleKey: config.customMT.key,
20
- }), (0, translate_1.default)(config.customMT));
22
+ }), (0, translate_1.default)({ baseUrl: config.baseUrl, folder, config: config.customMT, fileStore: config.fileStore }));
23
+ app.get('/file/download/custom-mt', (0, file_download_1.default)(config, config.customMT, 'custom-mt'));
21
24
  // TEMPORARY CODE: it needs to support old path
22
25
  app.post('/translate', (0, crowdin_client_1.default)({
23
26
  config,
24
27
  optional: false,
25
28
  checkSubscriptionExpiration: true,
26
- }), (0, translate_1.default)(config.customMT));
29
+ }), (0, translate_1.default)({ baseUrl: config.baseUrl, folder, config: config.customMT, fileStore: config.fileStore }));
27
30
  // END TEMPORARY CODE
28
31
  }
29
32
  exports.register = register;
@@ -1,14 +1,26 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
1
3
  import Crowdin, { SourceStringsModel } from '@crowdin/crowdin-api-client';
2
- import { CrowdinContextInfo, ModuleKey } from '../../types';
4
+ import { CrowdinContextInfo, FileStore, ModuleKey } from '../../types';
3
5
  export interface CustomMTLogic extends ModuleKey {
4
6
  withContext?: boolean;
7
+ splitStringsIntoChunks?: boolean;
5
8
  batchSize?: number;
6
9
  maskEntities?: boolean;
10
+ filesFolder?: string;
7
11
  translate: (client: Crowdin, context: CrowdinContextInfo, projectId: number | null, source: string, target: string, strings: CustomMtString[]) => Promise<string[]>;
8
12
  validate?: (client: Crowdin) => Promise<void>;
13
+ storeFile?: (fileContent: Buffer) => Promise<string>;
9
14
  }
10
15
  export interface CustomMTRequest {
11
- strings: CustomMtString[];
16
+ strings?: CustomMtString[];
17
+ stringsUrl?: string;
18
+ }
19
+ export interface CustomMTHandleOptions {
20
+ baseUrl: string;
21
+ folder: string;
22
+ config: CustomMTLogic;
23
+ fileStore?: FileStore;
12
24
  }
13
25
  export type CustomMtString = string | {
14
26
  id: number;
@@ -2,4 +2,4 @@
2
2
  import { Response } from 'express';
3
3
  import { CrowdinClientRequest } from '../../../types';
4
4
  import { CustomSpellcheckerModule } from '../types';
5
- export default function handle(customSpellchecker: CustomSpellcheckerModule): (req: 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;
5
+ export default function handle(customSpellchecker: CustomSpellcheckerModule): (req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -2,4 +2,4 @@
2
2
  import { Response } from 'express';
3
3
  import { CrowdinClientRequest } from '../../../types';
4
4
  import { CustomSpellcheckerModule } from '../types';
5
- export default function handle(customSpellchecker: CustomSpellcheckerModule): (req: 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;
5
+ export default function handle(customSpellchecker: CustomSpellcheckerModule): (req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -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));
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));
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));
22
+ app.use('/settings', (0, ui_module_1.default)({ config }), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule, config));
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));
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));
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));
54
+ app.use('/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true }), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule, config));
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));
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));
16
16
  }
17
17
  exports.register = register;
@@ -2,4 +2,4 @@
2
2
  import { Response } from 'express';
3
3
  import { CrowdinClientRequest } from '../../../types';
4
4
  import { ExternalQaCheckModule } from '../types';
5
- export default function handle(externalQaCheck: ExternalQaCheckModule): (req: 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;
5
+ export default function handle(externalQaCheck: ExternalQaCheckModule): (req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -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));
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));
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));
43
+ app.use('/settings', (0, ui_module_1.default)({ config, allowUnauthorized: true }), (0, render_ui_module_1.default)(qaCheck.settingsUiModule, config));
44
44
  // END TEMPORARY CODE
45
45
  }
46
46
  }
@@ -1,5 +1,10 @@
1
1
  /// <reference types="qs" />
2
2
  import { Response } from 'express';
3
- import { CrowdinClientRequest } from '../../../types';
3
+ import { CrowdinClientRequest, FileStore } from '../../../types';
4
4
  import { CustomFileFormatLogic } from '../types';
5
- export default function handle(baseUrl: string, folder: string, config: CustomFileFormatLogic): (req: 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;
5
+ export default function handle({ baseUrl, folder, config, fileStore, }: {
6
+ baseUrl: string;
7
+ folder: string;
8
+ config: CustomFileFormatLogic;
9
+ fileStore?: FileStore;
10
+ }): (req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -17,9 +17,11 @@ const path_1 = __importDefault(require("path"));
17
17
  const util_1 = require("../../../util");
18
18
  const files_1 = require("../util/files");
19
19
  const types_1 = require("../types");
20
- function handle(baseUrl, folder, config) {
21
- if (!fs_1.default.existsSync(path_1.default.join(folder, 'custom-file-format'))) {
22
- fs_1.default.mkdirSync(path_1.default.join(folder, 'custom-file-format'), { recursive: true });
20
+ function handle({ baseUrl, folder, config, fileStore, }) {
21
+ if (!fileStore) {
22
+ if (!fs_1.default.existsSync(path_1.default.join(folder, 'custom-file-format'))) {
23
+ fs_1.default.mkdirSync(path_1.default.join(folder, 'custom-file-format'), { recursive: true });
24
+ }
23
25
  }
24
26
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
25
27
  const baseFilesUrl = `${baseUrl}/file/download`;
@@ -43,12 +45,32 @@ function handle(baseUrl, folder, config) {
43
45
  let error;
44
46
  switch (body.jobType) {
45
47
  case types_1.ProcessFileJobType.BUILD_FILE:
46
- const buildFileResult = yield handleBuildFile(baseFilesUrl, folder, config, body, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id, file);
48
+ const buildFileResult = yield handleBuildFile({
49
+ baseUrl: baseFilesUrl,
50
+ dataFolder: folder,
51
+ config,
52
+ req: body,
53
+ client: req.crowdinApiClient,
54
+ context: req.crowdinContext,
55
+ projectId: req.crowdinContext.jwtPayload.context.project_id,
56
+ file,
57
+ fileStore,
58
+ });
47
59
  response = buildFileResult.response;
48
60
  error = buildFileResult.error;
49
61
  break;
50
62
  case types_1.ProcessFileJobType.PARSE_FILE:
51
- const parseFileResult = yield handleParseFile(baseFilesUrl, folder, config, body, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id, file);
63
+ const parseFileResult = yield handleParseFile({
64
+ baseUrl: baseFilesUrl,
65
+ dataFolder: folder,
66
+ config,
67
+ req: body,
68
+ client: req.crowdinApiClient,
69
+ context: req.crowdinContext,
70
+ projectId: req.crowdinContext.jwtPayload.context.project_id,
71
+ file,
72
+ fileStore,
73
+ });
52
74
  response = parseFileResult.response;
53
75
  error = parseFileResult.error;
54
76
  break;
@@ -59,7 +81,7 @@ function handle(baseUrl, folder, config) {
59
81
  }));
60
82
  }
61
83
  exports.default = handle;
62
- function handleBuildFile(baseUrl, dataFolder, config, req, client, context, projectId, file) {
84
+ function handleBuildFile({ baseUrl, dataFolder, config, req, client, context, projectId, file, fileStore, }) {
63
85
  return __awaiter(this, void 0, void 0, function* () {
64
86
  const response = {};
65
87
  if (!req.strings && !req.stringsUrl) {
@@ -88,19 +110,25 @@ function handleBuildFile(baseUrl, dataFolder, config, req, client, context, proj
88
110
  }
89
111
  else {
90
112
  let url;
91
- if (config.storeFile) {
92
- url = yield config.storeFile(res.contentFile);
113
+ if (fileStore) {
114
+ const fileRef = yield fileStore.storeFile(res.contentFile);
115
+ url = `${baseUrl}?file=${fileRef}`;
93
116
  }
94
117
  else {
95
- const storedFile = yield (0, files_1.storeFile)(res.contentFile, path_1.default.join(dataFolder, 'custom-file-format'));
96
- url = `${baseUrl}?file=${storedFile}`;
118
+ if (config.storeFile) {
119
+ url = yield config.storeFile(res.contentFile);
120
+ }
121
+ else {
122
+ const storedFile = yield (0, files_1.storeFile)(res.contentFile, path_1.default.join(dataFolder, 'custom-file-format'));
123
+ url = `${baseUrl}?file=${storedFile}`;
124
+ }
97
125
  }
98
126
  response.contentUrl = url;
99
127
  }
100
128
  return { response, error: res.error };
101
129
  });
102
130
  }
103
- function handleParseFile(baseUrl, dataFolder, config, req, client, context, projectId, file) {
131
+ function handleParseFile({ baseUrl, dataFolder, config, req, client, context, projectId, file, fileStore, }) {
104
132
  return __awaiter(this, void 0, void 0, function* () {
105
133
  const response = {};
106
134
  if (!config.parseFile || !file) {
@@ -117,12 +145,18 @@ function handleParseFile(baseUrl, dataFolder, config, req, client, context, proj
117
145
  }
118
146
  else {
119
147
  let url;
120
- if (config.storeFile) {
121
- url = yield config.storeFile(res.previewFile);
148
+ if (fileStore) {
149
+ const fileRef = yield fileStore.storeFile(res.previewFile);
150
+ url = `${baseUrl}?file=${fileRef}`;
122
151
  }
123
152
  else {
124
- const storedFile = yield (0, files_1.storeFile)(res.previewFile, path_1.default.join(dataFolder, 'custom-file-format'));
125
- url = `${baseUrl}?file=${storedFile}`;
153
+ if (config.storeFile) {
154
+ url = yield config.storeFile(res.previewFile);
155
+ }
156
+ else {
157
+ const storedFile = yield (0, files_1.storeFile)(res.previewFile, path_1.default.join(dataFolder, 'custom-file-format'));
158
+ url = `${baseUrl}?file=${storedFile}`;
159
+ }
126
160
  }
127
161
  response.previewUrl = url;
128
162
  }
@@ -145,12 +179,18 @@ function handleParseFile(baseUrl, dataFolder, config, req, client, context, proj
145
179
  }
146
180
  else {
147
181
  let url;
148
- if (config.storeFile) {
149
- url = yield config.storeFile(bufferData);
182
+ if (fileStore) {
183
+ const fileRef = yield fileStore.storeFile(bufferData);
184
+ url = `${baseUrl}?file=${fileRef}`;
150
185
  }
151
186
  else {
152
- const storedFile = yield (0, files_1.storeFile)(bufferData, path_1.default.join(dataFolder, 'custom-file-format'));
153
- url = `${baseUrl}?file=${storedFile}`;
187
+ if (config.storeFile) {
188
+ url = yield config.storeFile(bufferData);
189
+ }
190
+ else {
191
+ const storedFile = yield (0, files_1.storeFile)(bufferData, path_1.default.join(dataFolder, 'custom-file-format'));
192
+ url = `${baseUrl}?file=${storedFile}`;
193
+ }
154
194
  }
155
195
  response.stringsUrl = url;
156
196
  }
@@ -2,4 +2,4 @@
2
2
  import { Request, Response } from 'express';
3
3
  import { Config } from '../../../types';
4
4
  import { FileProcessLogic } from '../types';
5
- export default function handle(config: Config, processingConfig: FileProcessLogic, folderName: string): (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;
5
+ export default function handle(config: Config, processingConfig: FileProcessLogic, folderName: string): (req: Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | import("../../../types").CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -19,6 +19,11 @@ const logger_1 = require("../../../util/logger");
19
19
  function handle(config, processingConfig, folderName) {
20
20
  const folder = processingConfig.filesFolder || config.dbFolder;
21
21
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
22
+ if (config.fileStore) {
23
+ const fileContent = yield config.fileStore.getFile(req.query.file);
24
+ res.send(fileContent);
25
+ return;
26
+ }
22
27
  const filePath = path_1.default.join(folder, folderName, req.query.file);
23
28
  (0, logger_1.log)(`Downloading file ${filePath}`);
24
29
  res.download(filePath, function (err) {
@@ -2,4 +2,4 @@
2
2
  import { Response } from 'express';
3
3
  import { Config, CrowdinClientRequest } from '../../../types';
4
4
  import { FileImportExportLogic } from '../types';
5
- export default function handle(baseConfig: Config, config: FileImportExportLogic, folderName: string): (req: 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;
5
+ export default function handle(baseConfig: Config, config: FileImportExportLogic, folderName: string): (req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -19,8 +19,10 @@ const types_1 = require("../types");
19
19
  const files_1 = require("../util/files");
20
20
  function handle(baseConfig, config, folderName) {
21
21
  const folderPath = config.filesFolder || baseConfig.dbFolder;
22
- if (!fs_1.default.existsSync(path_1.default.join(folderPath, folderName))) {
23
- fs_1.default.mkdirSync(path_1.default.join(folderPath, folderName), { recursive: true });
22
+ if (!baseConfig.fileStore) {
23
+ if (!fs_1.default.existsSync(path_1.default.join(folderPath, folderName))) {
24
+ fs_1.default.mkdirSync(path_1.default.join(folderPath, folderName), { recursive: true });
25
+ }
24
26
  }
25
27
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
26
28
  var _a;
@@ -72,12 +74,18 @@ function handle(baseConfig, config, folderName) {
72
74
  }
73
75
  else {
74
76
  let url;
75
- if (config.storeFile) {
76
- url = yield config.storeFile(contentFile);
77
+ if (baseConfig.fileStore) {
78
+ const fileRef = yield baseConfig.fileStore.storeFile(contentFile);
79
+ url = `${baseFilesUrl}?file=${fileRef}`;
77
80
  }
78
81
  else {
79
- const storedFile = yield (0, files_1.storeFile)(contentFile, path_1.default.join(folderPath, folderName));
80
- url = `${baseFilesUrl}?file=${storedFile}`;
82
+ if (config.storeFile) {
83
+ url = yield config.storeFile(contentFile);
84
+ }
85
+ else {
86
+ const storedFile = yield (0, files_1.storeFile)(contentFile, path_1.default.join(folderPath, folderName));
87
+ url = `${baseFilesUrl}?file=${storedFile}`;
88
+ }
81
89
  }
82
90
  response.contentUrl = url;
83
91
  }
@@ -103,12 +111,18 @@ function handle(baseConfig, config, folderName) {
103
111
  }
104
112
  else {
105
113
  let url;
106
- if (config.storeFile) {
107
- url = yield config.storeFile(previewFile);
114
+ if (baseConfig.fileStore) {
115
+ const fileRef = yield baseConfig.fileStore.storeFile(previewFile);
116
+ url = `${baseFilesUrl}?file=${fileRef}`;
108
117
  }
109
118
  else {
110
- const storedFile = yield (0, files_1.storeFile)(previewFile, path_1.default.join(folderPath, folderName));
111
- url = `${baseFilesUrl}?file=${storedFile}`;
119
+ if (config.storeFile) {
120
+ url = yield config.storeFile(previewFile);
121
+ }
122
+ else {
123
+ const storedFile = yield (0, files_1.storeFile)(previewFile, path_1.default.join(folderPath, folderName));
124
+ url = `${baseFilesUrl}?file=${storedFile}`;
125
+ }
112
126
  }
113
127
  response.previewUrl = url;
114
128
  }
@@ -121,12 +135,18 @@ function handle(baseConfig, config, folderName) {
121
135
  }
122
136
  else {
123
137
  let url;
124
- if (config.storeFile) {
125
- url = yield config.storeFile(bufferData);
138
+ if (baseConfig.fileStore) {
139
+ const fileRef = yield baseConfig.fileStore.storeFile(bufferData);
140
+ url = `${baseFilesUrl}?file=${fileRef}`;
126
141
  }
127
142
  else {
128
- const storedFile = yield (0, files_1.storeFile)(bufferData, path_1.default.join(folderPath, folderName));
129
- url = `${baseFilesUrl}?file=${storedFile}`;
143
+ if (config.storeFile) {
144
+ url = yield config.storeFile(bufferData);
145
+ }
146
+ else {
147
+ const storedFile = yield (0, files_1.storeFile)(bufferData, path_1.default.join(folderPath, folderName));
148
+ url = `${baseFilesUrl}?file=${storedFile}`;
149
+ }
130
150
  }
131
151
  response.stringsUrl = url;
132
152
  }
@@ -2,4 +2,4 @@
2
2
  import { Response } from 'express';
3
3
  import { Config, CrowdinClientRequest } from '../../../types';
4
4
  import { TranslationsAlignmentLogic } from '../types';
5
- export default function handle(baseConfig: Config, config: TranslationsAlignmentLogic, folderName: string): (req: 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;
5
+ export default function handle(baseConfig: Config, config: TranslationsAlignmentLogic, folderName: string): (req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -21,13 +21,23 @@ function registerCustomFileFormat({ config, app }) {
21
21
  optional: false,
22
22
  checkSubscriptionExpiration: true,
23
23
  moduleKey: config.customFileFormat.key,
24
- }), (0, custom_file_format_1.default)(config.baseUrl, config.customFileFormat.filesFolder || config.dbFolder, config.customFileFormat));
24
+ }), (0, custom_file_format_1.default)({
25
+ baseUrl: config.baseUrl,
26
+ folder: config.customFileFormat.filesFolder || config.dbFolder,
27
+ config: config.customFileFormat,
28
+ fileStore: config.fileStore,
29
+ }));
25
30
  // TEMPORARY CODE: it needs to support old path
26
31
  app.post('/process', (0, crowdin_client_1.default)({
27
32
  config,
28
33
  optional: false,
29
34
  checkSubscriptionExpiration: true,
30
- }), (0, custom_file_format_1.default)(config.baseUrl, config.customFileFormat.filesFolder || config.dbFolder, config.customFileFormat));
35
+ }), (0, custom_file_format_1.default)({
36
+ baseUrl: config.baseUrl,
37
+ folder: config.customFileFormat.filesFolder || config.dbFolder,
38
+ config: config.customFileFormat,
39
+ fileStore: config.fileStore,
40
+ }));
31
41
  // END TEMPORARY CODE
32
42
  app.get('/file/download', (0, file_download_1.default)(config, config.customFileFormat, 'custom-file-format'));
33
43
  }
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
26
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
27
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -10,20 +33,41 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
33
  };
11
34
  Object.defineProperty(exports, "__esModule", { value: true });
12
35
  exports.applyFileProcessorsModuleDefaults = void 0;
13
- const client_s3_1 = require("@aws-sdk/client-s3");
14
- const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
36
+ function loadAwsSdk() {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ try {
39
+ const [s3Client, s3Presigner] = yield Promise.all([
40
+ Promise.resolve().then(() => __importStar(require('@aws-sdk/client-s3'))),
41
+ Promise.resolve().then(() => __importStar(require('@aws-sdk/s3-request-presigner'))),
42
+ ]);
43
+ return {
44
+ S3Client: s3Client.S3Client,
45
+ GetObjectCommand: s3Client.GetObjectCommand,
46
+ PutObjectCommand: s3Client.PutObjectCommand,
47
+ getSignedUrl: s3Presigner.getSignedUrl,
48
+ };
49
+ }
50
+ catch (_a) {
51
+ throw new Error('AWS SDK is not installed. To use S3 file storage, install required packages:\n' +
52
+ 'npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner');
53
+ }
54
+ });
55
+ }
15
56
  function applyFileProcessorsModuleDefaults(config, fileModule) {
16
57
  var _a, _b;
17
58
  const AWS_TMP_BUCKET_NAME = (_a = config.awsConfig) === null || _a === void 0 ? void 0 : _a.tmpBucketName;
18
59
  const AWS_REGION = (_b = config.awsConfig) === null || _b === void 0 ? void 0 : _b.region;
19
60
  if (AWS_TMP_BUCKET_NAME && AWS_REGION && !fileModule.storeFile) {
20
- const s3 = new client_s3_1.S3Client({ region: AWS_REGION });
61
+ let initPromise = null;
62
+ const getS3 = () => (initPromise !== null && initPromise !== void 0 ? initPromise : (initPromise = loadAwsSdk().then(sdk => ({ sdk, s3: new sdk.S3Client({ region: AWS_REGION }) }))));
21
63
  fileModule.storeFile = (content) => __awaiter(this, void 0, void 0, function* () {
64
+ const { sdk, s3 } = yield getS3();
65
+ const { GetObjectCommand, PutObjectCommand, getSignedUrl } = sdk;
22
66
  const fileName = `file-${config.identifier}-${Date.now()}`;
23
- const command = new client_s3_1.PutObjectCommand({ Bucket: AWS_TMP_BUCKET_NAME, Key: fileName, Body: content });
67
+ const command = new PutObjectCommand({ Bucket: AWS_TMP_BUCKET_NAME, Key: fileName, Body: content });
24
68
  yield s3.send(command);
25
- const getObjectCommand = new client_s3_1.GetObjectCommand({ Bucket: AWS_TMP_BUCKET_NAME, Key: fileName });
26
- return (0, s3_request_presigner_1.getSignedUrl)(s3, getObjectCommand, { expiresIn: 3600 });
69
+ const getObjectCommand = new GetObjectCommand({ Bucket: AWS_TMP_BUCKET_NAME, Key: fileName });
70
+ return getSignedUrl(s3, getObjectCommand, { expiresIn: 3600 });
27
71
  });
28
72
  }
29
73
  }
@@ -32,7 +32,8 @@ exports.storeFile = storeFile;
32
32
  function getFileContent(url) {
33
33
  return __awaiter(this, void 0, void 0, function* () {
34
34
  const response = (yield axios_1.default.get(url, { responseType: 'arraybuffer' })).data;
35
- return response;
35
+ // Support for both Node.js (returns Buffer) and Cloudflare Workers (returns ArrayBuffer)
36
+ return Buffer.isBuffer(response) ? response : Buffer.from(response);
36
37
  });
37
38
  }
38
39
  exports.getFileContent = getFileContent;
@@ -1,4 +1,4 @@
1
1
  /// <reference types="qs" />
2
2
  import { Config, CrowdinClientRequest } from '../types';
3
3
  import { Response } from 'express';
4
- export default function handle(config: Config): (req: 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;
4
+ export default function handle(config: Config): (req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -1,4 +1,4 @@
1
1
  /// <reference types="qs" />
2
2
  import { Config, CrowdinClientRequest } from '../types';
3
3
  import { Response } from 'express';
4
- export default function handle(config: Config): (req: 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;
4
+ export default function handle(config: Config): (req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -1,4 +1,4 @@
1
1
  /// <reference types="qs" />
2
2
  import { Request, Response } from 'express';
3
3
  import { Config } from '../types';
4
- export default function handle(config: Config): (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;
4
+ export default function handle(config: Config): (req: Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | import("../types").CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -2,4 +2,4 @@
2
2
  import { Response } from 'express';
3
3
  import { CrowdinClientRequest } from '../../../types';
4
4
  import { IntegrationLogic } from '../types';
5
- export default function handle(integration: IntegrationLogic): (req: 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;
5
+ export default function handle(integration: IntegrationLogic): (req: import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | CrowdinClientRequest, res: Response<any, Record<string, any>>, next: Function) => void;