@crowdin/app-project-module 0.66.1 → 0.68.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 (45) hide show
  1. package/README.md +3 -17
  2. package/out/index.js +25 -10
  3. package/out/middlewares/crowdin-client.d.ts +13 -2
  4. package/out/middlewares/crowdin-client.js +17 -3
  5. package/out/middlewares/ui-module.d.ts +5 -1
  6. package/out/middlewares/ui-module.js +5 -1
  7. package/out/modules/ai-prompt-provider/index.js +7 -2
  8. package/out/modules/ai-provider/handlers/chat-completions.js +75 -5
  9. package/out/modules/ai-provider/handlers/get-model-list.js +3 -2
  10. package/out/modules/ai-provider/index.js +13 -3
  11. package/out/modules/ai-provider/types.d.ts +5 -2
  12. package/out/modules/ai-tools/index.js +7 -2
  13. package/out/modules/ai-tools/types.d.ts +2 -2
  14. package/out/modules/api/api.js +66 -11
  15. package/out/modules/context-menu/index.js +1 -1
  16. package/out/modules/custom-mt/index.js +6 -1
  17. package/out/modules/custom-mt/types.d.ts +4 -2
  18. package/out/modules/custom-spell-check/index.js +14 -4
  19. package/out/modules/custom-spell-check/types.d.ts +2 -2
  20. package/out/modules/editor-right-panel/index.js +1 -1
  21. package/out/modules/external-qa-check/index.js +7 -2
  22. package/out/modules/external-qa-check/types.d.ts +2 -2
  23. package/out/modules/file-processing/index.js +30 -5
  24. package/out/modules/file-processing/types.d.ts +3 -2
  25. package/out/modules/file-processing/util/files.d.ts +1 -0
  26. package/out/modules/install.js +10 -2
  27. package/out/modules/integration/index.js +109 -18
  28. package/out/modules/integration/types.d.ts +2 -2
  29. package/out/modules/manifest.js +48 -22
  30. package/out/modules/modal/index.js +1 -1
  31. package/out/modules/organization-menu/index.js +1 -1
  32. package/out/modules/profile-resources-menu/index.js +1 -1
  33. package/out/modules/project-menu/index.js +1 -1
  34. package/out/modules/project-menu-crowdsource/index.js +1 -1
  35. package/out/modules/project-reports/index.js +1 -1
  36. package/out/modules/project-tools/index.js +1 -1
  37. package/out/static/css/crowdin-ui-colors.css +115 -0
  38. package/out/static/js/form.js +10 -10
  39. package/out/types.d.ts +16 -2
  40. package/out/util/handlebars.js +2 -2
  41. package/out/util/index.d.ts +0 -1
  42. package/out/util/index.js +1 -9
  43. package/out/views/main.handlebars +3 -19
  44. package/out/views/partials/head.handlebars +1 -0
  45. package/package.json +12 -12
package/README.md CHANGED
@@ -2,26 +2,12 @@
2
2
 
3
3
  Module that will automatically add all necessary endpoints for Crowdin App.
4
4
 
5
- :bookmark: See the [docs](/docs) for more information.
5
+ :bookmark: See the [docs](https://crowdin.github.io/app-project-module/) for more information.
6
6
 
7
7
  ## Contributing
8
8
 
9
- If you want to contribute please read the [Contributing](/CONTRIBUTING.md) guidelines.
9
+ If you would like to contribute please read the [Contributing](/CONTRIBUTING.md) guidelines.
10
10
 
11
11
  ## Seeking Assistance
12
12
 
13
- If you find any problems or would like to suggest a feature, please feel free to file an issue on Github at [Issues Page](https://github.com/crowdin/app-project-module/issues).
14
-
15
- If you've found an error in these samples, please [Contact Customer Success Service](https://crowdin.com/contacts).
16
-
17
- ## License
18
-
19
- <pre>
20
- The Crowdin App Project module is licensed under the MIT License.
21
- See the LICENSE.md file distributed with this work for additional
22
- information regarding copyright ownership.
23
-
24
- Except as contained in the LICENSE file, the name(s) of the above copyright
25
- holders shall not be used in advertising or otherwise to promote the sale,
26
- use or other dealings in this Software without prior written authorization.
27
- </pre>
13
+ If you find any problems or would like to suggest a feature, please feel free to file an issue on GitHub at [Issues Page](https://github.com/crowdin/app-project-module/issues) or [Contact Customer Success Service](https://crowdin.com/contacts).
package/out/index.js CHANGED
@@ -176,7 +176,7 @@ function addCrowdinEndpoints(app, clientConfig) {
176
176
  aiTools.registerAiToolWidgets({ config, app });
177
177
  externalQaCheck.register({ config, app });
178
178
  addFormSchema({ config, app });
179
- return Object.assign(Object.assign({}, exports.metadataStore), { establishCrowdinConnection: (authRequest) => {
179
+ return Object.assign(Object.assign({}, exports.metadataStore), { establishCrowdinConnection: (authRequest, moduleKey) => {
180
180
  let jwtToken = '';
181
181
  if (typeof authRequest === 'string') {
182
182
  jwtToken = authRequest;
@@ -184,7 +184,13 @@ function addCrowdinEndpoints(app, clientConfig) {
184
184
  else {
185
185
  jwtToken = (0, crowdin_client_1.getToken)(authRequest);
186
186
  }
187
- return (0, crowdin_client_1.prepareCrowdinRequest)(jwtToken, config);
187
+ return (0, crowdin_client_1.prepareCrowdinRequest)({
188
+ jwtToken,
189
+ config,
190
+ optional: false,
191
+ checkSubscriptionExpiration: false,
192
+ moduleKey,
193
+ });
188
194
  }, encryptCrowdinConnection: (data) => (0, util_1.encryptData)(config, JSON.stringify(data)), dencryptCrowdinConnection: (hash) => __awaiter(this, void 0, void 0, function* () {
189
195
  const { crowdinId, extra } = JSON.parse((0, util_1.decryptData)(config, hash));
190
196
  const credentials = yield storage.getStorage().getCrowdinCredentials(crowdinId);
@@ -197,18 +203,27 @@ function addCrowdinEndpoints(app, clientConfig) {
197
203
  }
198
204
  exports.addCrowdinEndpoints = addCrowdinEndpoints;
199
205
  function addFormSchema({ app, config }) {
200
- let moduleConfigWithForm;
201
- const shouldAddRoutes = Object.keys(config).some((moduleKey) => {
206
+ let moduleConfigWithForm = null;
207
+ for (const moduleKey of Object.keys(config)) {
202
208
  const moduleConfig = config[moduleKey];
203
209
  if ((0, form_schema_1.hasFormSchema)(moduleConfig)) {
204
210
  moduleConfigWithForm = (0, form_schema_1.getLowCodeUiConfigFromModuleConfig)(moduleConfig);
205
- return true;
211
+ break;
206
212
  }
207
- return false;
208
- });
209
- if (shouldAddRoutes) {
210
- app.get('/api/form-data', json_response_1.default, (0, crowdin_client_1.default)(config), (0, credentials_masker_1.getRequestCredentialsMasker)({ moduleConfig: moduleConfigWithForm }), (0, form_data_display_1.default)(config));
211
- app.post('/api/form-data', (0, crowdin_client_1.default)(config), (0, credentials_masker_1.postRequestCredentialsMasker)(moduleConfigWithForm), (0, form_data_save_1.default)(config));
213
+ }
214
+ if (moduleConfigWithForm) {
215
+ app.get('/api/form-data', json_response_1.default, (0, crowdin_client_1.default)({
216
+ config,
217
+ optional: false,
218
+ checkSubscriptionExpiration: true,
219
+ moduleKey: moduleConfigWithForm.key,
220
+ }), (0, credentials_masker_1.getRequestCredentialsMasker)({ moduleConfig: moduleConfigWithForm }), (0, form_data_display_1.default)(config));
221
+ app.post('/api/form-data', (0, crowdin_client_1.default)({
222
+ config,
223
+ optional: false,
224
+ checkSubscriptionExpiration: true,
225
+ moduleKey: moduleConfigWithForm.key,
226
+ }), (0, credentials_masker_1.postRequestCredentialsMasker)(moduleConfigWithForm), (0, form_data_save_1.default)(config));
212
227
  }
213
228
  }
214
229
  function convertClientConfig(clientConfig) {
@@ -3,12 +3,23 @@ import Crowdin from '@crowdin/crowdin-api-client';
3
3
  import { Response } from 'express';
4
4
  import { Config, CrowdinClientRequest, CrowdinContextInfo, SubscriptionInfo } from '../types';
5
5
  import { LogErrorFunction, LogFunction } from '../util/logger';
6
- export declare function prepareCrowdinRequest(jwtToken: string, config: Config, optional?: boolean, checkSubscriptionExpiration?: boolean): Promise<{
6
+ export declare function prepareCrowdinRequest({ jwtToken, config, optional, checkSubscriptionExpiration, moduleKey, }: {
7
+ jwtToken: string;
8
+ config: Config;
9
+ optional: boolean;
10
+ checkSubscriptionExpiration: boolean;
11
+ moduleKey: string[] | string | undefined;
12
+ }): Promise<{
7
13
  context: CrowdinContextInfo;
8
14
  logInfo: LogFunction;
9
15
  logError: LogErrorFunction;
10
16
  client?: Crowdin;
11
17
  subscriptionInfo?: SubscriptionInfo;
12
18
  }>;
13
- export default function handle(config: Config, optional?: boolean, checkSubscriptionExpiration?: boolean): (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;
19
+ export default function handle({ config, optional, checkSubscriptionExpiration, moduleKey, }: {
20
+ config: Config;
21
+ optional: boolean;
22
+ checkSubscriptionExpiration: boolean;
23
+ moduleKey?: string[] | string | undefined;
24
+ }): (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;
14
25
  export declare function getToken(req: CrowdinClientRequest): string | undefined;
@@ -17,7 +17,7 @@ const api_1 = require("../modules/api/api");
17
17
  const connection_1 = require("../util/connection");
18
18
  const logger_1 = require("../util/logger");
19
19
  const subscription_1 = require("../util/subscription");
20
- function prepareCrowdinRequest(jwtToken, config, optional = false, checkSubscriptionExpiration = true) {
20
+ function prepareCrowdinRequest({ jwtToken, config, optional = false, checkSubscriptionExpiration = true, moduleKey, }) {
21
21
  return __awaiter(this, void 0, void 0, function* () {
22
22
  (0, logger_1.log)('Validating jwt token from incoming request');
23
23
  const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(jwtToken, config.clientSecret, config.jwtValidationOptions);
@@ -37,6 +37,14 @@ function prepareCrowdinRequest(jwtToken, config, optional = false, checkSubscrip
37
37
  }
38
38
  throw new Error("Can't find organization by id");
39
39
  }
40
+ if (!!moduleKey && !!jwtPayload.module) {
41
+ if (typeof moduleKey === 'string' && moduleKey !== jwtPayload.module) {
42
+ throw new Error("Module key doesn't match");
43
+ }
44
+ if (Array.isArray(moduleKey) && !moduleKey.includes(jwtPayload.module)) {
45
+ throw new Error("Module key doesn't match");
46
+ }
47
+ }
40
48
  logInfo('Building crowdin client instance');
41
49
  const { client, token } = yield (0, connection_1.prepareCrowdinClient)({ config, credentials, autoRenew: true, context });
42
50
  let subscriptionInfo;
@@ -55,7 +63,7 @@ function prepareCrowdinRequest(jwtToken, config, optional = false, checkSubscrip
55
63
  });
56
64
  }
57
65
  exports.prepareCrowdinRequest = prepareCrowdinRequest;
58
- function handle(config, optional = false, checkSubscriptionExpiration = true) {
66
+ function handle({ config, optional = false, checkSubscriptionExpiration = true, moduleKey, }) {
59
67
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
60
68
  var _a;
61
69
  const jwtToken = getToken(req);
@@ -64,7 +72,13 @@ function handle(config, optional = false, checkSubscriptionExpiration = true) {
64
72
  return res.status(403).send({ error: 'Access denied' });
65
73
  }
66
74
  try {
67
- const data = yield prepareCrowdinRequest(jwtToken, config, optional, checkSubscriptionExpiration);
75
+ const data = yield prepareCrowdinRequest({
76
+ jwtToken,
77
+ config,
78
+ optional,
79
+ checkSubscriptionExpiration,
80
+ moduleKey,
81
+ });
68
82
  if ((_a = config.api) === null || _a === void 0 ? void 0 : _a.default) {
69
83
  data.context = (0, api_1.updateCrowdinContext)(req, data.context);
70
84
  }
@@ -1,4 +1,8 @@
1
1
  /// <reference types="qs" />
2
2
  import { Request, Response } from 'express';
3
3
  import { Config, UnauthorizedConfig } from '../types';
4
- export default function handle(config: Config | UnauthorizedConfig, allowUnauthorized?: boolean): (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, allowUnauthorized, moduleType, }: {
5
+ config: Config | UnauthorizedConfig;
6
+ allowUnauthorized?: boolean;
7
+ moduleType?: string | undefined;
8
+ }): (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;
@@ -15,7 +15,7 @@ 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
- function handle(config, allowUnauthorized = false) {
18
+ function handle({ config, allowUnauthorized = false, moduleType, }) {
19
19
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
20
20
  if (allowUnauthorized) {
21
21
  next();
@@ -32,6 +32,10 @@ function handle(config, allowUnauthorized = false) {
32
32
  (0, logger_1.log)('Validating jwt token from incoming request');
33
33
  const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(jwtToken, config.clientSecret, config.jwtValidationOptions);
34
34
  const id = `${jwtPayload.domain || jwtPayload.context.organization_id}`;
35
+ if (moduleType && jwtPayload.module && jwtPayload.module !== moduleType) {
36
+ (0, logger_1.temporaryErrorDebug)('Access denied: ui-module', req);
37
+ return res.status(403).send({ error: 'Access denied' });
38
+ }
35
39
  const context = {
36
40
  jwtPayload,
37
41
  clientId: (0, crowdin_apps_functions_1.constructCrowdinIdFromJwtPayload)(jwtPayload),
@@ -14,9 +14,14 @@ function register({ config, app }) {
14
14
  if (!config.aiPromptProvider) {
15
15
  return;
16
16
  }
17
- app.post('/prompt-provider/compile', json_response_1.default, (0, crowdin_client_1.default)(config), (0, compile_1.default)(config.aiPromptProvider));
17
+ app.post('/prompt-provider/compile', json_response_1.default, (0, crowdin_client_1.default)({
18
+ config,
19
+ optional: false,
20
+ checkSubscriptionExpiration: true,
21
+ moduleKey: config.aiPromptProvider.key,
22
+ }), (0, compile_1.default)(config.aiPromptProvider));
18
23
  if (config.aiPromptProvider.formSchema) {
19
- app.use('/prompt-provider/settings', (0, ui_module_1.default)(config, true), (0, render_ui_module_1.default)(config.aiPromptProvider));
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));
20
25
  }
21
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); });
22
27
  }
@@ -13,13 +13,43 @@ const util_1 = require("../../../util");
13
13
  const logger_1 = require("../../../util/logger");
14
14
  const files_1 = require("../../integration/util/files");
15
15
  const util_2 = require("../util");
16
+ // more about roles in AI messages https://platform.openai.com/docs/api-reference/chat/create#chat-create-messages
17
+ // Crowdin documentation https://support.crowdin.com/developer/crowdin-apps-module-custom-ai/#expected-response-from-the-app
18
+ const ROLES = {
19
+ assistant: 'assistant',
20
+ };
21
+ const DEFAULT_ROLE = ROLES.assistant;
22
+ const getErrorStatus = (e) => {
23
+ if (typeof e === 'object' && 'status' in e && typeof e.status === 'number') {
24
+ return e.status;
25
+ }
26
+ return 500;
27
+ };
28
+ const getErrorCode = (e) => {
29
+ if (typeof e === 'object' && 'code' in e) {
30
+ return e.code;
31
+ }
32
+ return undefined;
33
+ };
16
34
  function handle(aiProvider) {
17
35
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
36
+ let isStream = false;
18
37
  try {
19
38
  let choices;
20
39
  let message;
21
40
  let data;
22
- const { crowdinApiClient: client, crowdinContext: context, body: { messages, model, action, responseFormat: { type: responseFormatType } = { type: undefined } }, } = req;
41
+ const chunks = [];
42
+ const { crowdinApiClient: client, crowdinContext: context, body: { messages, model, action, stream, responseFormat: { type: responseFormatType } = { type: undefined }, }, } = req;
43
+ isStream = !!stream;
44
+ const startStream = () => {
45
+ if (!res.headersSent) {
46
+ res.writeHead(200, {
47
+ Connection: 'keep-alive',
48
+ 'Cache-Control': 'no-cache',
49
+ 'Content-Type': 'text/event-stream',
50
+ });
51
+ }
52
+ };
23
53
  const result = yield aiProvider.chatCompletions({
24
54
  messages,
25
55
  model,
@@ -28,7 +58,32 @@ function handle(aiProvider) {
28
58
  client,
29
59
  context,
30
60
  req,
61
+ isStream,
62
+ sendEvent: ({ content, role }) => __awaiter(this, void 0, void 0, function* () {
63
+ if (!isStream) {
64
+ chunks.push({ content, role });
65
+ return;
66
+ }
67
+ startStream();
68
+ const message = {
69
+ choices: [
70
+ {
71
+ delta: {
72
+ role: role || DEFAULT_ROLE,
73
+ content,
74
+ },
75
+ },
76
+ ],
77
+ };
78
+ res.write(`data: ${JSON.stringify(message)}\n\n`);
79
+ }),
31
80
  });
81
+ if (isStream) {
82
+ startStream();
83
+ res.write('[DONE]');
84
+ res.end();
85
+ return;
86
+ }
32
87
  if ((0, files_1.isExtendedResultType)(result)) {
33
88
  data = result.data;
34
89
  message = result.message;
@@ -36,10 +91,18 @@ function handle(aiProvider) {
36
91
  else {
37
92
  data = result;
38
93
  }
94
+ if (chunks.length) {
95
+ data = [
96
+ {
97
+ role: chunks[0].role || DEFAULT_ROLE,
98
+ content: chunks.map((chunk) => chunk.content).join(''),
99
+ },
100
+ ];
101
+ }
39
102
  if (data && data.length > 0) {
40
103
  choices = data.map((message) => ({
41
104
  message: {
42
- role: message.role || 'assistant',
105
+ role: message.role || DEFAULT_ROLE,
43
106
  content: message.content,
44
107
  },
45
108
  }));
@@ -50,10 +113,17 @@ function handle(aiProvider) {
50
113
  if (req.logError) {
51
114
  req.logError(e);
52
115
  }
53
- if ((0, util_2.isRateLimitError)(e)) {
54
- res.status(429);
116
+ if (!res.headersSent) {
117
+ res.status((0, util_2.isRateLimitError)(e) ? 429 : getErrorStatus(e));
118
+ }
119
+ if (isStream && res.headersSent) {
120
+ res.write(`data: ${JSON.stringify({ error: { message: (0, logger_1.getErrorMessage)(e), code: getErrorCode(e) } })}\n\n`);
121
+ res.write('[DONE]');
122
+ res.end();
123
+ }
124
+ else {
125
+ res.send({ error: { message: (0, logger_1.getErrorMessage)(e) } });
55
126
  }
56
- res.send({ error: { message: (0, logger_1.getErrorMessage)(e) } });
57
127
  }
58
128
  }));
59
129
  }
@@ -22,12 +22,13 @@ function handle(aiProvider) {
22
22
  context: req.crowdinContext,
23
23
  });
24
24
  const data = modelList.map((model) => {
25
- var _a, _b, _c;
25
+ var _a, _b, _c, _d;
26
26
  return ({
27
27
  id: model.id,
28
28
  supportsJsonMode: (_a = model.supportsJsonMode) !== null && _a !== void 0 ? _a : false,
29
29
  supportsFunctionCalling: (_b = model.supportsFunctionCalling) !== null && _b !== void 0 ? _b : false,
30
- contextWindowLimit: (_c = model.contextWindowLimit) !== null && _c !== void 0 ? _c : exports.CONTEXT_WINDOW_LIMIT,
30
+ supportsStreaming: (_c = model.supportsStreaming) !== null && _c !== void 0 ? _c : false,
31
+ contextWindowLimit: (_d = model.contextWindowLimit) !== null && _d !== void 0 ? _d : exports.CONTEXT_WINDOW_LIMIT,
31
32
  });
32
33
  });
33
34
  res.send({ data });
@@ -16,10 +16,20 @@ function register({ config, app }) {
16
16
  return;
17
17
  }
18
18
  if (config.aiProvider.settingsUiModule) {
19
- app.use('/settings', (0, ui_module_1.default)(config, true), (0, render_ui_module_1.default)(config.aiProvider.settingsUiModule));
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));
20
20
  }
21
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); });
22
- app.get('/models', json_response_1.default, (0, crowdin_client_1.default)(config), (0, get_model_list_1.default)(config.aiProvider));
23
- app.post('/completions', json_response_1.default, (0, crowdin_client_1.default)(config), (0, chat_completions_1.default)(config.aiProvider));
22
+ app.get('/models', json_response_1.default, (0, crowdin_client_1.default)({
23
+ config,
24
+ optional: false,
25
+ checkSubscriptionExpiration: true,
26
+ moduleKey: config.aiProvider.key,
27
+ }), (0, get_model_list_1.default)(config.aiProvider));
28
+ app.post('/completions', json_response_1.default, (0, crowdin_client_1.default)({
29
+ config,
30
+ optional: false,
31
+ checkSubscriptionExpiration: true,
32
+ moduleKey: config.aiProvider.key,
33
+ }), (0, chat_completions_1.default)(config.aiProvider));
24
34
  }
25
35
  exports.register = register;
@@ -1,7 +1,7 @@
1
- import { CrowdinClientRequest, CrowdinContextInfo, Environments, UiModule } from '../../types';
1
+ import { CrowdinClientRequest, CrowdinContextInfo, Environments, ModuleKey, UiModule } from '../../types';
2
2
  import Crowdin from '@crowdin/crowdin-api-client';
3
3
  import { ExtendedResult } from '../integration/types';
4
- export interface AiProviderModule extends Environments {
4
+ export interface AiProviderModule extends Environments, ModuleKey {
5
5
  /**
6
6
  * module name
7
7
  */
@@ -25,6 +25,8 @@ export interface AiProviderModule extends Environments {
25
25
  client: Crowdin;
26
26
  context: CrowdinContextInfo;
27
27
  req: CrowdinClientRequest;
28
+ isStream: boolean;
29
+ sendEvent: (chunk: Message) => Promise<void>;
28
30
  }) => Promise<Message[] | ExtendedResult<Message[]>>;
29
31
  /**
30
32
  * provides a list of available model
@@ -38,6 +40,7 @@ export interface SupportedModels {
38
40
  id: string;
39
41
  supportsJsonMode?: boolean;
40
42
  supportsFunctionCalling?: boolean;
43
+ supportsStreaming?: boolean;
41
44
  contextWindowLimit?: number;
42
45
  }
43
46
  export interface Message {
@@ -17,7 +17,12 @@ function registerAiTools({ config, app }) {
17
17
  const tools = Array.isArray(config.aiTools) ? config.aiTools : [config.aiTools];
18
18
  for (const tool of tools) {
19
19
  if ((0, util_1.isUniqueFunctionName)(tool)) {
20
- app.post((0, util_1.getAiToolUrl)(tool), json_response_1.default, (0, crowdin_client_1.default)(config), (0, tool_calls_1.default)(tool));
20
+ app.post((0, util_1.getAiToolUrl)(tool), json_response_1.default, (0, crowdin_client_1.default)({
21
+ config,
22
+ optional: false,
23
+ checkSubscriptionExpiration: true,
24
+ moduleKey: tool.key,
25
+ }), (0, tool_calls_1.default)(tool));
21
26
  }
22
27
  else {
23
28
  throw new Error(`The function name '${tool.function.name}' is not unique within aiTools and aiToolsWidget`);
@@ -32,7 +37,7 @@ function registerAiToolWidgets({ config, app }) {
32
37
  const tools = Array.isArray(config.aiToolsWidget) ? config.aiToolsWidget : [config.aiToolsWidget];
33
38
  for (const tool of tools) {
34
39
  if ((0, util_1.isUniqueFunctionName)(tool)) {
35
- app.use((0, util_1.getAiToolWidgetUrl)(tool), (0, ui_module_1.default)(config), (0, render_ui_module_1.default)(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));
36
41
  }
37
42
  else {
38
43
  throw new Error(`The function name '${tool.function.name}' is not unique within aiTools and aiToolsWidget`);
@@ -1,8 +1,8 @@
1
- import { CrowdinClientRequest, CrowdinContextInfo, Environments, UiModule } from '../../types';
1
+ import { CrowdinClientRequest, CrowdinContextInfo, Environments, ModuleKey, UiModule } from '../../types';
2
2
  import Crowdin from '@crowdin/crowdin-api-client';
3
3
  export interface AiToolWidget extends BaseAiTool, UiModule {
4
4
  }
5
- export interface AiTool extends BaseAiTool {
5
+ export interface AiTool extends BaseAiTool, ModuleKey {
6
6
  /**
7
7
  * function to handle requests
8
8
  */
@@ -171,7 +171,12 @@ function addDefaultApiEndpoints(app, config) {
171
171
  * data:
172
172
  * $ref: '#/components/schemas/CrowdinFiles'
173
173
  */
174
- app.get('/crowdin-files', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, crowdin_files_1.default)(config, config.projectIntegration));
174
+ app.get('/crowdin-files', json_response_1.default, (0, crowdin_client_1.default)({
175
+ config,
176
+ optional: false,
177
+ checkSubscriptionExpiration: true,
178
+ moduleKey: config.projectIntegration.key,
179
+ }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, crowdin_files_1.default)(config, config.projectIntegration));
175
180
  /**
176
181
  * @openapi
177
182
  * /file-progress:
@@ -200,7 +205,12 @@ function addDefaultApiEndpoints(app, config) {
200
205
  * data:
201
206
  * $ref: '#/components/schemas/FileProgress'
202
207
  */
203
- app.get('/file-progress', (0, crowdin_client_1.default)(config), (0, crowdin_file_progress_1.default)(config.projectIntegration));
208
+ app.get('/file-progress', (0, crowdin_client_1.default)({
209
+ config,
210
+ optional: false,
211
+ checkSubscriptionExpiration: true,
212
+ moduleKey: config.projectIntegration.key,
213
+ }), (0, crowdin_file_progress_1.default)(config.projectIntegration));
204
214
  /**
205
215
  * @openapi
206
216
  * /integration-files:
@@ -222,7 +232,12 @@ function addDefaultApiEndpoints(app, config) {
222
232
  * $ref: '#/components/schemas/IntegrationFiles'
223
233
  *
224
234
  */
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));
235
+ app.get('/integration-files', json_response_1.default, (0, crowdin_client_1.default)({
236
+ config,
237
+ optional: false,
238
+ checkSubscriptionExpiration: true,
239
+ moduleKey: config.projectIntegration.key,
240
+ }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, integration_data_1.default)(config.projectIntegration));
226
241
  /**
227
242
  * @openapi
228
243
  * /crowdin-update:
@@ -245,7 +260,12 @@ function addDefaultApiEndpoints(app, config) {
245
260
  * data:
246
261
  * $ref: '#/components/schemas/UpdateResponse'
247
262
  */
248
- app.post('/crowdin-update', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, crowdin_update_1.default)(config, config.projectIntegration));
263
+ app.post('/crowdin-update', json_response_1.default, (0, crowdin_client_1.default)({
264
+ config,
265
+ optional: false,
266
+ checkSubscriptionExpiration: true,
267
+ moduleKey: config.projectIntegration.key,
268
+ }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, crowdin_update_1.default)(config, config.projectIntegration));
249
269
  /**
250
270
  * @openapi
251
271
  * /integration-update:
@@ -268,7 +288,12 @@ function addDefaultApiEndpoints(app, config) {
268
288
  * data:
269
289
  * $ref: '#/components/schemas/UpdateResponse'
270
290
  */
271
- app.post('/integration-update', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, integration_update_1.default)(config, config.projectIntegration));
291
+ app.post('/integration-update', json_response_1.default, (0, crowdin_client_1.default)({
292
+ config,
293
+ optional: false,
294
+ checkSubscriptionExpiration: true,
295
+ moduleKey: config.projectIntegration.key,
296
+ }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, integration_update_1.default)(config, config.projectIntegration));
272
297
  /**
273
298
  * @openapi
274
299
  * /settings:
@@ -289,7 +314,12 @@ function addDefaultApiEndpoints(app, config) {
289
314
  * data:
290
315
  * $ref: '#/components/schemas/SettingsResponse'
291
316
  */
292
- app.get('/settings', (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, settings_1.default)());
317
+ app.get('/settings', (0, crowdin_client_1.default)({
318
+ config,
319
+ optional: false,
320
+ checkSubscriptionExpiration: true,
321
+ moduleKey: config.projectIntegration.key,
322
+ }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, settings_1.default)());
293
323
  /**
294
324
  * @openapi
295
325
  * /settings:
@@ -307,7 +337,12 @@ function addDefaultApiEndpoints(app, config) {
307
337
  * 204:
308
338
  * description: 'Application Settings was successfully update'
309
339
  */
310
- app.post('/settings', (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, settings_save_1.default)(config, config.projectIntegration));
340
+ app.post('/settings', (0, crowdin_client_1.default)({
341
+ config,
342
+ optional: false,
343
+ checkSubscriptionExpiration: true,
344
+ moduleKey: config.projectIntegration.key,
345
+ }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, settings_save_1.default)(config, config.projectIntegration));
311
346
  /**
312
347
  * @openapi
313
348
  * /sync-settings:
@@ -338,7 +373,12 @@ function addDefaultApiEndpoints(app, config) {
338
373
  * - { $ref: '#/components/schemas/CrowdinSyncSettingsResponse' }
339
374
  * - { $ref: '#/components/schemas/IntegrationSyncSettingsResponse' }
340
375
  */
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)());
376
+ app.get('/sync-settings', json_response_1.default, (0, crowdin_client_1.default)({
377
+ config,
378
+ optional: false,
379
+ checkSubscriptionExpiration: true,
380
+ moduleKey: config.projectIntegration.key,
381
+ }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, sync_settings_1.default)());
342
382
  /**
343
383
  * @openapi
344
384
  * /sync-settings:
@@ -356,7 +396,12 @@ function addDefaultApiEndpoints(app, config) {
356
396
  * 204:
357
397
  * description: 'Application Sync Settings was successfully update'
358
398
  */
359
- app.post('/sync-settings', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, sync_settings_save_1.default)(config, config.projectIntegration));
399
+ app.post('/sync-settings', json_response_1.default, (0, crowdin_client_1.default)({
400
+ config,
401
+ optional: false,
402
+ checkSubscriptionExpiration: true,
403
+ moduleKey: config.projectIntegration.key,
404
+ }), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, sync_settings_save_1.default)(config, config.projectIntegration));
360
405
  if (config.projectIntegration.loginForm) {
361
406
  /**
362
407
  * @openapi
@@ -376,7 +421,12 @@ function addDefaultApiEndpoints(app, config) {
376
421
  * data:
377
422
  * $ref: '#/components/schemas/LoginFieldsResponse'
378
423
  */
379
- app.get('/login-fields', json_response_1.default, (0, crowdin_client_1.default)(config), (req, res) => {
424
+ app.get('/login-fields', json_response_1.default, (0, crowdin_client_1.default)({
425
+ config,
426
+ optional: false,
427
+ checkSubscriptionExpiration: true,
428
+ moduleKey: config.projectIntegration.key,
429
+ }), (req, res) => {
380
430
  var _a;
381
431
  let fields = [];
382
432
  if ((_a = config.projectIntegration) === null || _a === void 0 ? void 0 : _a.loginForm.fields) {
@@ -401,7 +451,12 @@ function addDefaultApiEndpoints(app, config) {
401
451
  * 204:
402
452
  * description: 'Login successful'
403
453
  */
404
- app.post('/login', (0, crowdin_client_1.default)(config, false, false), (0, integration_login_1.default)(config, config.projectIntegration));
454
+ app.post('/login', (0, crowdin_client_1.default)({
455
+ config,
456
+ optional: false,
457
+ checkSubscriptionExpiration: false,
458
+ moduleKey: config.projectIntegration.key,
459
+ }), (0, integration_login_1.default)(config, config.projectIntegration));
405
460
  }
406
461
  }
407
462
  }
@@ -11,7 +11,7 @@ function register({ config, app }) {
11
11
  var _a, _b;
12
12
  const allowUnauthorized = !(0, util_1.isAuthorizedConfig)(config);
13
13
  if (((_a = config.contextMenu) === null || _a === void 0 ? void 0 : _a.uiPath) || ((_b = config.contextMenu) === null || _b === void 0 ? void 0 : _b.formSchema)) {
14
- app.use('/context', (0, ui_module_1.default)(config, allowUnauthorized), (0, render_ui_module_1.default)(config.contextMenu));
14
+ app.use('/context', (0, ui_module_1.default)({ config, allowUnauthorized, moduleType: config.contextMenu.key }), (0, render_ui_module_1.default)(config.contextMenu));
15
15
  }
16
16
  }
17
17
  exports.register = register;
@@ -12,6 +12,11 @@ function register({ config, app }) {
12
12
  return;
13
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
- app.post('/translate', (0, crowdin_client_1.default)(config), (0, translate_1.default)(config.customMT));
15
+ app.post('/translate', (0, crowdin_client_1.default)({
16
+ config,
17
+ optional: false,
18
+ checkSubscriptionExpiration: true,
19
+ moduleKey: config.customMT.key,
20
+ }), (0, translate_1.default)(config.customMT));
16
21
  }
17
22
  exports.register = register;
@@ -1,7 +1,9 @@
1
1
  import Crowdin, { SourceStringsModel } from '@crowdin/crowdin-api-client';
2
- import { CrowdinContextInfo } from '../../types';
3
- export interface CustomMTLogic {
2
+ import { CrowdinContextInfo, ModuleKey } from '../../types';
3
+ export interface CustomMTLogic extends ModuleKey {
4
4
  withContext?: boolean;
5
+ batchSize?: number;
6
+ maskEntities?: boolean;
5
7
  translate: (client: Crowdin, context: CrowdinContextInfo, projectId: number, source: string, target: string, strings: CustomMtString[]) => Promise<string[]>;
6
8
  validate?: (client: Crowdin) => Promise<void>;
7
9
  }