@crowdin/app-project-module 1.10.0 → 1.11.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.
- package/out/modules/api/api.js +323 -18
- package/out/modules/api/components.d.ts +222 -19
- package/out/modules/api/components.js +222 -19
- package/out/modules/integration/handlers/crowdin-file-progress.js +5 -2
- package/out/modules/integration/handlers/integration-data.js +14 -2
- package/out/modules/integration/handlers/settings-save.js +29 -1
- package/out/modules/integration/handlers/settings-schema.d.ts +3 -0
- package/out/modules/integration/handlers/settings-schema.js +29 -0
- package/out/modules/integration/handlers/sync-settings.js +11 -3
- package/out/util/index.js +3 -1
- package/out/util/logger.d.ts +1 -0
- package/out/util/logger.js +7 -0
- package/package.json +13 -13
|
@@ -34,13 +34,16 @@ function handle(integration) {
|
|
|
34
34
|
res.send(progress);
|
|
35
35
|
}
|
|
36
36
|
catch (e) {
|
|
37
|
+
const errorWithData = new logger_1.AppUserModuleError(e, {
|
|
38
|
+
fileId,
|
|
39
|
+
});
|
|
37
40
|
yield (0, logger_1.handleUserError)({
|
|
38
41
|
action: 'Get Crowdin files progress',
|
|
39
|
-
error:
|
|
42
|
+
error: errorWithData,
|
|
40
43
|
crowdinId: req.crowdinContext.crowdinId,
|
|
41
44
|
clientId: req.crowdinContext.clientId,
|
|
42
45
|
});
|
|
43
|
-
throw
|
|
46
|
+
throw errorWithData;
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
49
|
else {
|
|
@@ -103,10 +103,22 @@ function handle(integration) {
|
|
|
103
103
|
crowdinId,
|
|
104
104
|
clientId,
|
|
105
105
|
});
|
|
106
|
-
|
|
106
|
+
// Different response structure for API (Crowdin wraps) vs UI
|
|
107
|
+
if (req.isApiCall) {
|
|
108
|
+
res.send({ files: [], message: (e === null || e === void 0 ? void 0 : e.message) || e });
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
res.send({ data: [], message: (e === null || e === void 0 ? void 0 : e.message) || e });
|
|
112
|
+
}
|
|
107
113
|
throw e;
|
|
108
114
|
}
|
|
109
115
|
req.logInfo(`Integration data response ${JSON.stringify(files, null, 2)}`);
|
|
110
|
-
|
|
116
|
+
// Different response structure for API (Crowdin wraps) vs UI
|
|
117
|
+
if (req.isApiCall) {
|
|
118
|
+
res.send({ files, message, stopPagination });
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
res.send({ data: files, message, stopPagination });
|
|
122
|
+
}
|
|
111
123
|
}));
|
|
112
124
|
}
|
|
@@ -20,7 +20,6 @@ const job_1 = require("../util/job");
|
|
|
20
20
|
const types_2 = require("../util/types");
|
|
21
21
|
function handle(config, integration) {
|
|
22
22
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
23
|
-
const settings = req.body.config;
|
|
24
23
|
if (req.isApiCall && !req.body.config) {
|
|
25
24
|
return res.status(400).json({
|
|
26
25
|
error: {
|
|
@@ -28,6 +27,34 @@ function handle(config, integration) {
|
|
|
28
27
|
},
|
|
29
28
|
});
|
|
30
29
|
}
|
|
30
|
+
if (req.isApiCall && typeof req.body.config !== 'object') {
|
|
31
|
+
return res.status(400).json({
|
|
32
|
+
error: {
|
|
33
|
+
message: 'Parameter "config" must be an object',
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const settings = req.body.config;
|
|
38
|
+
// Validate that all config keys exist in schema
|
|
39
|
+
if (req.isApiCall && integration.getConfiguration) {
|
|
40
|
+
const projectId = req.crowdinContext.jwtPayload.context.project_id;
|
|
41
|
+
const schema = yield integration.getConfiguration({
|
|
42
|
+
projectId,
|
|
43
|
+
client: req.crowdinApiClient,
|
|
44
|
+
credentials: req.integrationCredentials,
|
|
45
|
+
settings: req.integrationSettings,
|
|
46
|
+
clientId: req.crowdinContext.clientId,
|
|
47
|
+
});
|
|
48
|
+
const validKeys = new Set(schema.filter((field) => 'key' in field).map((field) => field.key));
|
|
49
|
+
const invalidKeys = Object.keys(settings).filter((key) => !validKeys.has(key));
|
|
50
|
+
if (invalidKeys.length > 0) {
|
|
51
|
+
return res.status(400).json({
|
|
52
|
+
error: {
|
|
53
|
+
message: `Invalid configuration keys: ${invalidKeys.join(', ')}. Use GET /settings/schema to see available fields.`,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
31
58
|
if (integration.validateSettings) {
|
|
32
59
|
const validationResult = yield integration.validateSettings({
|
|
33
60
|
client: req.crowdinApiClient,
|
|
@@ -55,6 +82,7 @@ function handle(config, integration) {
|
|
|
55
82
|
client: req.crowdinApiClient,
|
|
56
83
|
jobType: types_2.JobClientType.HIDDEN,
|
|
57
84
|
jobStoreType: integration.jobStoreType,
|
|
85
|
+
initiatedBy: String(req.crowdinContext.jwtPayload.context.user_id),
|
|
58
86
|
jobCallback: () => __awaiter(this, void 0, void 0, function* () {
|
|
59
87
|
req.logInfo(`Saving settings ${JSON.stringify(settings, null, 2)}`);
|
|
60
88
|
const integrationConfig = yield (0, storage_1.getStorage)().getIntegrationConfig(clientId);
|
|
@@ -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
|
+
exports.default = handle;
|
|
13
|
+
const util_1 = require("../../../util");
|
|
14
|
+
function handle(integration) {
|
|
15
|
+
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
if (!integration.getConfiguration) {
|
|
17
|
+
return res.send([]);
|
|
18
|
+
}
|
|
19
|
+
const projectId = req.crowdinContext.jwtPayload.context.project_id;
|
|
20
|
+
const configurationFields = yield integration.getConfiguration({
|
|
21
|
+
projectId,
|
|
22
|
+
client: req.crowdinApiClient,
|
|
23
|
+
credentials: req.integrationCredentials,
|
|
24
|
+
settings: req.integrationSettings,
|
|
25
|
+
clientId: req.crowdinContext.clientId,
|
|
26
|
+
});
|
|
27
|
+
res.send(configurationFields);
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
@@ -12,10 +12,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.default = handle;
|
|
13
13
|
const storage_1 = require("../../../storage");
|
|
14
14
|
const util_1 = require("../../../util");
|
|
15
|
+
const types_1 = require("../types");
|
|
15
16
|
function handle() {
|
|
16
17
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
17
18
|
let files = {};
|
|
18
|
-
const provider = req.params.provider || req.body.provider;
|
|
19
|
+
const provider = req.params.provider || req.query.provider || req.body.provider;
|
|
19
20
|
if (req.isApiCall && !provider) {
|
|
20
21
|
return res.status(400).json({
|
|
21
22
|
error: {
|
|
@@ -23,12 +24,19 @@ function handle() {
|
|
|
23
24
|
},
|
|
24
25
|
});
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
+
if (!Object.values(types_1.Provider).includes(provider)) {
|
|
28
|
+
return res.status(400).json({
|
|
29
|
+
error: {
|
|
30
|
+
message: `Invalid provider. Must be one of: ${Object.values(types_1.Provider).join(', ')}`,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
req.logInfo(`Loading auto-sync files for provider ${provider}`);
|
|
27
35
|
const syncSettings = yield (0, storage_1.getStorage)().getSyncSettingsByProvider(req.crowdinContext.clientId, provider);
|
|
28
36
|
if (syncSettings) {
|
|
29
37
|
files = JSON.parse(syncSettings.files) || [];
|
|
30
38
|
}
|
|
31
|
-
req.logInfo(`Returning sync
|
|
39
|
+
req.logInfo(`Returning auto-sync files ${JSON.stringify(files, null, 2)}`);
|
|
32
40
|
res.send(files);
|
|
33
41
|
}));
|
|
34
42
|
}
|
package/out/util/index.js
CHANGED
|
@@ -103,7 +103,9 @@ function handleError(err, req, res) {
|
|
|
103
103
|
}
|
|
104
104
|
if (!res.headersSent) {
|
|
105
105
|
const errorMessage = { message: (0, logger_1.getErrorMessage)(err), code };
|
|
106
|
-
|
|
106
|
+
const isApiCall = isCrowdinClientRequest(req) && req.isApiCall;
|
|
107
|
+
const isUiIntegration = 'integrationCredentials' in req && !isApiCall;
|
|
108
|
+
if (isUiIntegration) {
|
|
107
109
|
const html = (0, jsx_renderer_1.renderJSXOnClient)({ name: 'error', props: errorMessage });
|
|
108
110
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
109
111
|
res.send(html);
|
package/out/util/logger.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export declare class AppModuleError extends Error {
|
|
|
25
25
|
data: any;
|
|
26
26
|
appData: any;
|
|
27
27
|
isAxiosError: boolean;
|
|
28
|
+
code?: number;
|
|
28
29
|
constructor(error: CustomAxiosError | Error | string, data?: any);
|
|
29
30
|
}
|
|
30
31
|
export declare class AppUserModuleError extends AppModuleError {
|
package/out/util/logger.js
CHANGED
|
@@ -197,6 +197,7 @@ function getErrorMessage(err) {
|
|
|
197
197
|
}
|
|
198
198
|
class AppModuleError extends Error {
|
|
199
199
|
constructor(error, data) {
|
|
200
|
+
var _a;
|
|
200
201
|
super(typeof error === 'string' ? error : error.message);
|
|
201
202
|
this.isAxiosError = false;
|
|
202
203
|
this.name = 'AppModuleError';
|
|
@@ -209,6 +210,12 @@ class AppModuleError extends Error {
|
|
|
209
210
|
}
|
|
210
211
|
if (isAxiosError(error)) {
|
|
211
212
|
this.isAxiosError = true;
|
|
213
|
+
// Extract HTTP status code from axios error
|
|
214
|
+
this.code = ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) || error.status;
|
|
215
|
+
}
|
|
216
|
+
else if (error.code && typeof error.code === 'number') {
|
|
217
|
+
// If error already has a numeric code property (e.g., CodeError)
|
|
218
|
+
this.code = error.code;
|
|
212
219
|
}
|
|
213
220
|
}
|
|
214
221
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crowdin/app-project-module",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
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",
|
|
@@ -10,20 +10,20 @@
|
|
|
10
10
|
"import": "./out/index.js",
|
|
11
11
|
"types": "./out/index.d.ts"
|
|
12
12
|
},
|
|
13
|
-
"./functions
|
|
14
|
-
"require": "./out/util/app-functions
|
|
15
|
-
"import": "./out/util/app-functions
|
|
16
|
-
"types": "./out/util/app-functions
|
|
17
|
-
},
|
|
18
|
-
"./functions/token": {
|
|
19
|
-
"require": "./out/util/app-functions/token.js",
|
|
20
|
-
"import": "./out/util/app-functions/token.js",
|
|
21
|
-
"types": "./out/util/app-functions/token.d.ts"
|
|
13
|
+
"./functions/*": {
|
|
14
|
+
"require": "./out/util/app-functions/*.js",
|
|
15
|
+
"import": "./out/util/app-functions/*.js",
|
|
16
|
+
"types": "./out/util/app-functions/*.d.ts"
|
|
22
17
|
},
|
|
23
18
|
"./out/*": {
|
|
24
|
-
"require": "./out
|
|
25
|
-
"import": "./out
|
|
26
|
-
"types": "./out
|
|
19
|
+
"require": "./out/*.js",
|
|
20
|
+
"import": "./out/*.js",
|
|
21
|
+
"types": "./out/*.d.ts"
|
|
22
|
+
},
|
|
23
|
+
"./modules/*": {
|
|
24
|
+
"require": "./out/modules/*/types.js",
|
|
25
|
+
"import": "./out/modules/*/types.js",
|
|
26
|
+
"types": "./out/modules/*/types.d.ts"
|
|
27
27
|
}
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|