@crowdin/app-project-module 0.20.5 → 0.20.7
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.
- package/README.md +11 -0
- package/out/middlewares/crowdin-client.js +1 -1
- package/out/middlewares/ui-module.js +1 -1
- package/out/models/index.d.ts +5 -1
- package/out/storage/mysql.js +19 -11
- package/out/storage/postgre.js +19 -13
- package/out/util/index.d.ts +1 -0
- package/out/util/index.js +18 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -43,6 +43,7 @@ In both options you will need to provide Crowdin App configuration file. Please
|
|
|
43
43
|
- [Custom MT](#custom-mt)
|
|
44
44
|
- [Profile Resources Menu](#profile-resources-menu)
|
|
45
45
|
- [Other modules](#other-modules)
|
|
46
|
+
- [Other options](#other-options)
|
|
46
47
|
- [Contributing](#contributing)
|
|
47
48
|
- [Seeking Assistance](#seeking-assistance)
|
|
48
49
|
- [License](#license)
|
|
@@ -768,6 +769,16 @@ const configuration = {
|
|
|
768
769
|
crowdinModule.createApp(configuration);
|
|
769
770
|
```
|
|
770
771
|
|
|
772
|
+
## Other options
|
|
773
|
+
|
|
774
|
+
### Options for Crowdin JWT token validation
|
|
775
|
+
|
|
776
|
+
```js
|
|
777
|
+
configuration.jwtValidationOptions = {
|
|
778
|
+
jwtValidationOptions: false, //ignore check if jwt is expired or not
|
|
779
|
+
};
|
|
780
|
+
```
|
|
781
|
+
|
|
771
782
|
## Contributing
|
|
772
783
|
|
|
773
784
|
If you want to contribute please read the [Contributing](/CONTRIBUTING.md) guidelines.
|
|
@@ -28,7 +28,7 @@ function getToken(req) {
|
|
|
28
28
|
function prepareCrowdinRequest(jwtToken, config, optional = false, checkSubscriptionExpiration = true) {
|
|
29
29
|
return __awaiter(this, void 0, void 0, function* () {
|
|
30
30
|
(0, util_1.log)('Validating jwt token from incoming request', config.logger);
|
|
31
|
-
const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(jwtToken, config.clientSecret);
|
|
31
|
+
const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(jwtToken, config.clientSecret, config.jwtValidationOptions);
|
|
32
32
|
const context = {
|
|
33
33
|
jwtPayload,
|
|
34
34
|
clientId: (0, crowdin_apps_functions_1.constructCrowdinIdFromJwtPayload)(jwtPayload),
|
|
@@ -20,7 +20,7 @@ function handle(config) {
|
|
|
20
20
|
return res.status(403).send({ error: 'Access denied' });
|
|
21
21
|
}
|
|
22
22
|
(0, util_1.log)('Validating jwt token from incoming request', config.logger);
|
|
23
|
-
const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(tokenJwt, config.clientSecret);
|
|
23
|
+
const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(tokenJwt, config.clientSecret, config.jwtValidationOptions);
|
|
24
24
|
const id = `${jwtPayload.domain || jwtPayload.context.organization_id}`;
|
|
25
25
|
(0, util_1.log)('Loading crowdin credentials', config.logger);
|
|
26
26
|
const credentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(id);
|
package/out/models/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Crowdin, { LanguagesModel, SourceFilesModel, SourceStringsModel } from '@crowdin/crowdin-api-client';
|
|
2
|
-
import { JwtPayload } from '@crowdin/crowdin-apps-functions';
|
|
2
|
+
import { JwtPayload, VerifyOptions } from '@crowdin/crowdin-apps-functions';
|
|
3
3
|
import { Request } from 'express';
|
|
4
4
|
import { MySQLStorageConfig } from '../storage/mysql';
|
|
5
5
|
import { PostgreStorageConfig } from '../storage/postgre';
|
|
@@ -16,6 +16,10 @@ export interface Config extends ImagePath {
|
|
|
16
16
|
* Secret to encrypt/decrypt credentials (by default @clientSecret will be used)
|
|
17
17
|
*/
|
|
18
18
|
cryptoSecret?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Options to validate Crowdin JWT token
|
|
21
|
+
*/
|
|
22
|
+
jwtValidationOptions?: VerifyOptions;
|
|
19
23
|
/**
|
|
20
24
|
* https url where an app is reachable from the internet (e.g. the one that ngrok generates for us)
|
|
21
25
|
*/
|
package/out/storage/mysql.js
CHANGED
|
@@ -13,6 +13,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.MySQLStorage = void 0;
|
|
16
|
+
const util_1 = require("../util");
|
|
16
17
|
class MySQLStorage {
|
|
17
18
|
constructor(config) {
|
|
18
19
|
this.mysql = require('mysql2/promise');
|
|
@@ -24,19 +25,26 @@ class MySQLStorage {
|
|
|
24
25
|
}
|
|
25
26
|
executeQuery(command) {
|
|
26
27
|
return __awaiter(this, void 0, void 0, function* () {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return res;
|
|
33
|
-
}
|
|
34
|
-
catch (e) {
|
|
35
|
-
if (connection) {
|
|
28
|
+
return (0, util_1.executeWithRetry)(() => __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
let connection;
|
|
30
|
+
try {
|
|
31
|
+
connection = yield this.mysql.createConnection(this.config);
|
|
32
|
+
const res = yield command(connection);
|
|
36
33
|
yield connection.end();
|
|
34
|
+
return res;
|
|
37
35
|
}
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (connection) {
|
|
38
|
+
try {
|
|
39
|
+
yield connection.end();
|
|
40
|
+
}
|
|
41
|
+
catch (nestedError) {
|
|
42
|
+
throw nestedError;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}));
|
|
40
48
|
});
|
|
41
49
|
}
|
|
42
50
|
migrate() {
|
package/out/storage/postgre.js
CHANGED
|
@@ -12,6 +12,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.PostgreStorage = void 0;
|
|
14
14
|
const pg_1 = require("pg");
|
|
15
|
+
const util_1 = require("../util");
|
|
15
16
|
class PostgreStorage {
|
|
16
17
|
constructor(config) {
|
|
17
18
|
this.dbPromise = new Promise((res, rej) => {
|
|
@@ -22,19 +23,24 @@ class PostgreStorage {
|
|
|
22
23
|
}
|
|
23
24
|
executeQuery(command) {
|
|
24
25
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
return (0, util_1.executeWithRetry)(() => __awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
const client = new pg_1.Client(this.config);
|
|
28
|
+
try {
|
|
29
|
+
yield client.connect();
|
|
30
|
+
const res = yield command(client);
|
|
31
|
+
yield client.end();
|
|
32
|
+
return res;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
try {
|
|
36
|
+
yield client.end();
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
catch (nestedError) {
|
|
40
|
+
throw nestedError;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}));
|
|
38
44
|
});
|
|
39
45
|
}
|
|
40
46
|
migrate() {
|
package/out/util/index.d.ts
CHANGED
|
@@ -9,3 +9,4 @@ export declare function getMessage(err: any): any;
|
|
|
9
9
|
export declare function runAsyncWrapper(callback: Function, onError?: (e: any) => void): (req: Request, res: Response, next: Function) => void;
|
|
10
10
|
export declare function encryptData(config: Config, data: string): string;
|
|
11
11
|
export declare function decryptData(config: Config, data: string): string;
|
|
12
|
+
export declare function executeWithRetry<T>(func: () => Promise<T>, numOfRetries?: number): Promise<T>;
|
package/out/util/index.js
CHANGED
|
@@ -28,7 +28,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
28
28
|
});
|
|
29
29
|
};
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
-
exports.decryptData = exports.encryptData = exports.runAsyncWrapper = exports.getMessage = exports.log = exports.CodeError = void 0;
|
|
31
|
+
exports.executeWithRetry = exports.decryptData = exports.encryptData = exports.runAsyncWrapper = exports.getMessage = exports.log = exports.CodeError = void 0;
|
|
32
32
|
const crypto = __importStar(require("crypto-js"));
|
|
33
33
|
const storage_1 = require("../storage");
|
|
34
34
|
class CodeError extends Error {
|
|
@@ -103,3 +103,20 @@ function decryptData(config, data) {
|
|
|
103
103
|
return crypto.AES.decrypt(data, config.cryptoSecret || config.clientSecret).toString(crypto.enc.Utf8);
|
|
104
104
|
}
|
|
105
105
|
exports.decryptData = decryptData;
|
|
106
|
+
function executeWithRetry(func, numOfRetries = 2) {
|
|
107
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
108
|
+
for (let i = 0; i <= numOfRetries; i++) {
|
|
109
|
+
try {
|
|
110
|
+
const result = yield func();
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
if (i === numOfRetries) {
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
throw new Error('Failed to process request with retry');
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
exports.executeWithRetry = executeWithRetry;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crowdin/app-project-module",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.7",
|
|
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",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"test": "echo \"test not implemented\""
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@crowdin/crowdin-apps-functions": "0.1.
|
|
15
|
+
"@crowdin/crowdin-apps-functions": "0.1.6",
|
|
16
16
|
"@types/pg": "^8.6.5",
|
|
17
17
|
"crypto-js": "^4.0.0",
|
|
18
18
|
"express": "4.17.1",
|