@crowdin/app-project-module 0.42.0 → 0.43.1

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.
@@ -0,0 +1,4 @@
1
+ /// <reference types="qs" />
2
+ import { Response } from 'express';
3
+ import { CrowdinClientRequest, CustomSpellcheckerModule } from '../../models';
4
+ 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;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const util_1 = require("../../util");
13
+ const logger_1 = require("../../util/logger");
14
+ function handle(customSpellchecker) {
15
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
+ try {
17
+ const data = yield customSpellchecker.getSupportedLanguage({
18
+ client: req.crowdinApiClient,
19
+ context: req.crowdinContext,
20
+ });
21
+ res.send({ data });
22
+ }
23
+ catch (e) {
24
+ req.logError(e);
25
+ res.send({ error: { message: (0, logger_1.getErrorMessage)(e) } });
26
+ }
27
+ }));
28
+ }
29
+ exports.default = handle;
@@ -0,0 +1,4 @@
1
+ /// <reference types="qs" />
2
+ import { Response } from 'express';
3
+ import { CrowdinClientRequest, CustomSpellcheckerModule } from '../../models';
4
+ 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;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const util_1 = require("../../util");
13
+ const logger_1 = require("../../util/logger");
14
+ function handle(customSpellchecker) {
15
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
+ const body = req.body;
17
+ (0, logger_1.log)('Received request for custom spellcheck');
18
+ (0, logger_1.log)(`Language ${body.language}, Payload ${JSON.stringify(body, null, 2)}`);
19
+ try {
20
+ const response = yield customSpellchecker.runSpellCheck({
21
+ client: req.crowdinApiClient,
22
+ context: req.crowdinContext,
23
+ language: body.language,
24
+ texts: body.texts,
25
+ });
26
+ res.send({ data: response.texts, error: response.error ? { message: response.error } : undefined });
27
+ }
28
+ catch (e) {
29
+ req.logError(e);
30
+ res.send({ error: { message: (0, logger_1.getErrorMessage)(e) } });
31
+ }
32
+ }));
33
+ }
34
+ exports.default = handle;
@@ -198,6 +198,12 @@ function handle(config) {
198
198
  if (config.api) {
199
199
  modules['api'] = (0, api_1.getApiManifest)(config, config.api);
200
200
  }
201
+ if (config.customSpellchecker) {
202
+ const uiModule = config.customSpellchecker.settingsUiModule;
203
+ modules['custom-spellchecker'] = [
204
+ Object.assign({ key: config.identifier + '-spellchecker', name: config.customSpellchecker.name || config.name, description: config.customSpellchecker.description || config.description, listSupportedLanguagesUrl: '/languages', checkSpellingUrl: '/spellcheck', environments: config.customSpellchecker.environments }, (uiModule ? { url: '/settings/' + (uiModule.fileName || 'index.html') } : {})),
205
+ ];
206
+ }
201
207
  const events = {
202
208
  installed: '/installed',
203
209
  uninstall: '/uninstall',
package/out/index.js CHANGED
@@ -70,6 +70,8 @@ const user_errors_1 = __importDefault(require("./handlers/integration/user-error
70
70
  const manifest_1 = __importDefault(require("./handlers/manifest"));
71
71
  const subscription_paid_1 = __importDefault(require("./handlers/subscription-paid"));
72
72
  const uninstall_1 = __importDefault(require("./handlers/uninstall"));
73
+ const get_languages_list_1 = __importDefault(require("./handlers/custom-spell-check/get-languages-list"));
74
+ const spell_check_1 = __importDefault(require("./handlers/custom-spell-check/spell-check"));
73
75
  const crowdin_client_1 = __importStar(require("./middlewares/crowdin-client"));
74
76
  const integration_credentials_1 = __importDefault(require("./middlewares/integration-credentials"));
75
77
  const json_response_1 = __importDefault(require("./middlewares/json-response"));
@@ -285,6 +287,13 @@ function addCrowdinEndpoints(app, clientConfig) {
285
287
  }
286
288
  (0, api_1.addSwagerApiDocumentation)(app, config);
287
289
  }
290
+ if (config.customSpellchecker) {
291
+ if (config.customSpellchecker.settingsUiModule) {
292
+ app.use('/settings', (0, ui_module_1.default)(config, config.customSpellchecker.settingsUiModule.allowUnauthorized), (0, render_ui_module_1.default)(config.customSpellchecker.settingsUiModule));
293
+ }
294
+ app.get('/languages', json_response_1.default, (0, crowdin_client_1.default)(config), (0, get_languages_list_1.default)(config.customSpellchecker));
295
+ app.post('/spellcheck', json_response_1.default, (0, crowdin_client_1.default)(config), (0, spell_check_1.default)(config.customSpellchecker));
296
+ }
288
297
  if (Object.keys(config).some((moduleKey) => {
289
298
  const moduleConfig = config[moduleKey];
290
299
  return typeof moduleConfig === 'object' && moduleConfig.hasOwnProperty('formSchema');
@@ -164,6 +164,7 @@ export interface ClientConfig extends ImagePath {
164
164
  * Not necessary to configure if environment variables AWS_REGION and AWS_TMP_BUCKET_NAME are properly set.
165
165
  */
166
166
  awsConfig?: AWSConfig;
167
+ customSpellchecker?: CustomSpellcheckerModule;
167
168
  }
168
169
  export type Config = ClientConfig & {
169
170
  baseUrl: string;
@@ -933,6 +934,60 @@ export interface ApiModule {
933
934
  endpoints?: ApiEndpoints[];
934
935
  docFile?: string;
935
936
  }
937
+ export interface CustomSpellCheckRequest {
938
+ language: string;
939
+ texts: string[];
940
+ }
941
+ export type SpellCheckCategory = 'typography' | 'casing' | 'grammar' | 'typos' | 'punctuation' | 'confused_words' | 'redundancy' | 'style' | 'gender_neutrality' | 'semantics' | 'colloquialisms' | 'wikipedia' | 'barbarism' | 'misc';
942
+ export interface SupportedLanguage {
943
+ code: string;
944
+ name: string;
945
+ }
946
+ export interface SpellCheckMatch {
947
+ category: SpellCheckCategory;
948
+ message: string;
949
+ shortMessage: string;
950
+ offset: number;
951
+ length: number;
952
+ replacements: string[];
953
+ }
954
+ export interface CustomSpellCheckResponse {
955
+ texts: {
956
+ text: string;
957
+ matches: SpellCheckMatch[];
958
+ }[];
959
+ error?: string;
960
+ }
961
+ export interface CustomSpellcheckerModule extends Environments {
962
+ /**
963
+ * module description
964
+ */
965
+ description?: string;
966
+ /**
967
+ * module name
968
+ */
969
+ name?: string;
970
+ /**
971
+ * Settings UI module
972
+ */
973
+ settingsUiModule?: UiModule;
974
+ /**
975
+ * function to get list of supported languages that are supports by current spellchecker
976
+ */
977
+ getSupportedLanguage: ({ client, context, }: {
978
+ client: Crowdin;
979
+ context: CrowdinContextInfo;
980
+ }) => Promise<SupportedLanguage[]>;
981
+ /**
982
+ * function to check spelling
983
+ */
984
+ runSpellCheck: ({ client, context, language, texts, }: {
985
+ client: Crowdin;
986
+ context: CrowdinContextInfo;
987
+ language: string;
988
+ texts: string[];
989
+ }) => Promise<CustomSpellCheckResponse>;
990
+ }
936
991
  export interface Logger {
937
992
  enabled: boolean;
938
993
  log?: (message: string, context?: CrowdinContextInfo) => void;
@@ -497,7 +497,7 @@ class MySQLStorage {
497
497
  const id = (0, uuid_1.v4)();
498
498
  yield this.dbPromise;
499
499
  yield this.executeQuery((connection) => connection.execute(`
500
- INSERT INTO jobs(id, integration_id, crowdin_id, type, payload, title, created_at)
500
+ INSERT INTO job(id, integration_id, crowdin_id, type, payload, title, created_at)
501
501
  VALUES (?, ?, ?, ?, ?, ?, ?)
502
502
  `, [id, integrationId, crowdinId, type, payload, title, Date.now().toString()]));
503
503
  return id;
@@ -167,10 +167,9 @@ class PostgreStorage {
167
167
  integration_id varchar not null,
168
168
  crowdin_id varchar not null,
169
169
  type varchar not null,
170
- payload varchar null,
171
170
  title varchar null,
172
- progress int 0,
173
- status varchar '${job_1.JobStatus.CREATED}',
171
+ progress int default 0,
172
+ status varchar default '${job_1.JobStatus.CREATED}',
174
173
  payload varchar null,
175
174
  info varchar null,
176
175
  data varchar null,
@@ -502,7 +501,10 @@ class PostgreStorage {
502
501
  updateIntegrationConfig(integrationId, config) {
503
502
  return __awaiter(this, void 0, void 0, function* () {
504
503
  yield this.dbPromise;
505
- yield this.executeQuery((client) => client.query('UPDATE integration_settings SET config = $1 WHERE id = $2', [config, integrationId]));
504
+ yield this.executeQuery((client) => client.query('UPDATE integration_settings SET config = $1 WHERE integration_id = $2', [
505
+ config,
506
+ integrationId,
507
+ ]));
506
508
  });
507
509
  }
508
510
  createJob({ integrationId, crowdinId, type, payload, title }) {
@@ -543,7 +545,7 @@ class PostgreStorage {
543
545
  }
544
546
  if (info) {
545
547
  updateFields.push('info = $' + updateParams.length.toString());
546
- updateParams.push(data);
548
+ updateParams.push(info);
547
549
  }
548
550
  updateParams.push(id);
549
551
  yield this.dbPromise;
@@ -561,7 +563,7 @@ class PostgreStorage {
561
563
  const res = yield client.query(`
562
564
  SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status,
563
565
  title, info, payload, data, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
564
- FROM jobs
566
+ FROM job
565
567
  WHERE id = $1
566
568
  `, [id]);
567
569
  return res === null || res === void 0 ? void 0 : res.rows[0];
@@ -575,7 +577,7 @@ class PostgreStorage {
575
577
  const res = yield client.query(`
576
578
  SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status,
577
579
  title, info, payload, data, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
578
- FROM jobs
580
+ FROM job
579
581
  WHERE integration_id = $1 AND crowdin_id = $2 AND finished_at is NULL
580
582
  `, [integrationId, crowdinId]);
581
583
  return (res === null || res === void 0 ? void 0 : res.rows) || [];
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.42.0",
3
+ "version": "0.43.1",
4
4
  "description": "Module that generates for you all common endpoints for serving standalone Crowdin App",
5
5
  "main": "out/index.js",
6
6
  "types": "out/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tsc -p ./ && cp -R views out && cp -R static out && cp logo.png out && rollup -c rollup.config.mjs",
9
9
  "build-main": "tsc -p ./ && cp -R views out && cp -R static out && cp logo.png out",
10
+ "watch-main": "tsc --watch -p ./ && cp -R views out && cp -R static out && cp logo.png out",
10
11
  "lint": "eslint --fix \"{src,tests}/**/*.{js,ts}\"",
11
12
  "prettier": "prettier --config .prettierrc src/**/*.ts --write",
12
13
  "lint-ci": "eslint \"{src,tests}/**/*.{js,ts}\"",