@crowdin/app-project-module 0.82.0 → 0.83.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/index.js +43 -17
- package/out/middlewares/render-ui-module.js +6 -2
- package/out/modules/integration/handlers/oauth-login.js +3 -1
- package/out/modules/integration/handlers/oauth-url.js +1 -1
- package/out/modules/integration/util/cron.js +1 -1
- package/out/modules/manifest.js +1 -1
- package/out/modules/status.d.ts +4 -0
- package/out/modules/status.js +74 -0
- package/out/static/js/form.js +11 -11
- package/out/storage/index.d.ts +2 -3
- package/out/storage/index.js +3 -3
- package/out/storage/mysql.d.ts +1 -1
- package/out/storage/mysql.js +11 -2
- package/out/storage/postgre.d.ts +1 -1
- package/out/storage/postgre.js +11 -2
- package/out/storage/sqlite.d.ts +1 -1
- package/out/storage/sqlite.js +11 -2
- package/out/types.d.ts +12 -0
- package/package.json +2 -1
package/out/index.js
CHANGED
|
@@ -37,6 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
38
|
exports.addCrowdinEndpoints = exports.createApp = exports.metadataStore = exports.express = exports.UserPermissions = exports.Scope = exports.ProjectPermissions = exports.maskKey = exports.postRequestCredentialsMasker = exports.getRequestCredentialsMasker = void 0;
|
|
39
39
|
const logsFormatter = __importStar(require("@crowdin/logs-formatter"));
|
|
40
|
+
const express_rate_limit_1 = require("express-rate-limit");
|
|
40
41
|
const path_1 = require("path");
|
|
41
42
|
const crowdin_client_1 = __importStar(require("./middlewares/crowdin-client"));
|
|
42
43
|
const json_response_1 = __importDefault(require("./middlewares/json-response"));
|
|
@@ -46,6 +47,7 @@ const install_1 = __importDefault(require("./modules/install"));
|
|
|
46
47
|
const manifest_1 = __importDefault(require("./modules/manifest"));
|
|
47
48
|
const subscription_paid_1 = __importDefault(require("./modules/subscription-paid"));
|
|
48
49
|
const uninstall_1 = __importDefault(require("./modules/uninstall"));
|
|
50
|
+
const status_1 = __importDefault(require("./modules/status"));
|
|
49
51
|
const storage = __importStar(require("./storage"));
|
|
50
52
|
const types_1 = require("./types");
|
|
51
53
|
const util_1 = require("./util");
|
|
@@ -94,6 +96,15 @@ exports.metadataStore = {
|
|
|
94
96
|
return storage.getStorage().getMetadata(id);
|
|
95
97
|
},
|
|
96
98
|
saveMetadata: (id, metadata, crowdinId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
99
|
+
if (!crowdinId) {
|
|
100
|
+
console.warn('Warning: The crowdinId parameter in saveMetadata will be required. Please update your code to provide this parameter.');
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const crowdinCredentials = yield storage.getStorage().getCrowdinCredentials(crowdinId);
|
|
104
|
+
if (!crowdinCredentials) {
|
|
105
|
+
console.error('Invalid crowdinId parameter: You can get your crowdinId from the JWT payload');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
97
108
|
const existing = yield storage.getStorage().getMetadata(id);
|
|
98
109
|
if (existing) {
|
|
99
110
|
yield storage.getStorage().updateMetadata(id, metadata, crowdinId);
|
|
@@ -121,6 +132,7 @@ function createApp(clientConfig) {
|
|
|
121
132
|
}
|
|
122
133
|
exports.createApp = createApp;
|
|
123
134
|
function addCrowdinEndpoints(app, clientConfig) {
|
|
135
|
+
var _a, _b, _c;
|
|
124
136
|
const config = convertClientConfig(clientConfig);
|
|
125
137
|
if (!config.disableGlobalErrorHandling) {
|
|
126
138
|
handleUncaughtErrors();
|
|
@@ -146,6 +158,21 @@ function addCrowdinEndpoints(app, clientConfig) {
|
|
|
146
158
|
app.set('view engine', 'handlebars');
|
|
147
159
|
app.get((0, util_1.getLogoUrl)(), (req, res) => res.sendFile(config.imagePath));
|
|
148
160
|
app.get('/manifest.json', json_response_1.default, (0, manifest_1.default)(config));
|
|
161
|
+
if (((_a = config === null || config === void 0 ? void 0 : config.enableStatusPage) === null || _a === void 0 ? void 0 : _a.database) || ((_b = config === null || config === void 0 ? void 0 : config.enableStatusPage) === null || _b === void 0 ? void 0 : _b.filesystem)) {
|
|
162
|
+
app.set('trust proxy', 1);
|
|
163
|
+
const limiter = (0, express_rate_limit_1.rateLimit)({
|
|
164
|
+
windowMs: 60 * 1000,
|
|
165
|
+
limit: ((_c = config.enableStatusPage) === null || _c === void 0 ? void 0 : _c.rateLimit) || 10,
|
|
166
|
+
standardHeaders: true,
|
|
167
|
+
legacyHeaders: false,
|
|
168
|
+
message: {
|
|
169
|
+
status: 429,
|
|
170
|
+
error: 'Too Many Requests',
|
|
171
|
+
message: 'Rate limit exceeded. Please try again later.',
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
app.get('/status', limiter, (0, status_1.default)(config));
|
|
175
|
+
}
|
|
149
176
|
if (!(0, subscription_1.isAppFree)(config)) {
|
|
150
177
|
app.post('/subscription-paid', (0, subscription_paid_1.default)());
|
|
151
178
|
}
|
|
@@ -220,28 +247,26 @@ function addCrowdinEndpoints(app, clientConfig) {
|
|
|
220
247
|
}
|
|
221
248
|
exports.addCrowdinEndpoints = addCrowdinEndpoints;
|
|
222
249
|
function addFormSchema({ app, config }) {
|
|
223
|
-
let moduleConfigWithForm = null;
|
|
224
250
|
for (const moduleKey of Object.keys(config)) {
|
|
225
251
|
const moduleConfig = config[moduleKey];
|
|
226
252
|
if ((0, form_schema_1.hasFormSchema)(moduleConfig)) {
|
|
227
|
-
moduleConfigWithForm = (0, form_schema_1.getLowCodeUiConfigFromModuleConfig)(moduleConfig);
|
|
228
|
-
|
|
253
|
+
const moduleConfigWithForm = (0, form_schema_1.getLowCodeUiConfigFromModuleConfig)(moduleConfig);
|
|
254
|
+
if (moduleConfigWithForm) {
|
|
255
|
+
app.get(`/api/${moduleConfigWithForm.key}/form-data`, json_response_1.default, (0, crowdin_client_1.default)({
|
|
256
|
+
config,
|
|
257
|
+
optional: false,
|
|
258
|
+
checkSubscriptionExpiration: true,
|
|
259
|
+
moduleKey: moduleConfigWithForm.key,
|
|
260
|
+
}), (0, credentials_masker_1.getRequestCredentialsMasker)({ moduleConfig: moduleConfigWithForm }), (0, form_data_display_1.default)(config));
|
|
261
|
+
app.post(`/api/${moduleConfigWithForm.key}/form-data`, (0, crowdin_client_1.default)({
|
|
262
|
+
config,
|
|
263
|
+
optional: false,
|
|
264
|
+
checkSubscriptionExpiration: true,
|
|
265
|
+
moduleKey: moduleConfigWithForm.key,
|
|
266
|
+
}), (0, credentials_masker_1.postRequestCredentialsMasker)(moduleConfigWithForm), (0, form_data_save_1.default)(config));
|
|
267
|
+
}
|
|
229
268
|
}
|
|
230
269
|
}
|
|
231
|
-
if (moduleConfigWithForm) {
|
|
232
|
-
app.get('/api/form-data', json_response_1.default, (0, crowdin_client_1.default)({
|
|
233
|
-
config,
|
|
234
|
-
optional: false,
|
|
235
|
-
checkSubscriptionExpiration: true,
|
|
236
|
-
moduleKey: moduleConfigWithForm.key,
|
|
237
|
-
}), (0, credentials_masker_1.getRequestCredentialsMasker)({ moduleConfig: moduleConfigWithForm }), (0, form_data_display_1.default)(config));
|
|
238
|
-
app.post('/api/form-data', (0, crowdin_client_1.default)({
|
|
239
|
-
config,
|
|
240
|
-
optional: false,
|
|
241
|
-
checkSubscriptionExpiration: true,
|
|
242
|
-
moduleKey: moduleConfigWithForm.key,
|
|
243
|
-
}), (0, credentials_masker_1.postRequestCredentialsMasker)(moduleConfigWithForm), (0, form_data_save_1.default)(config));
|
|
244
|
-
}
|
|
245
270
|
}
|
|
246
271
|
function convertClientConfig(clientConfig) {
|
|
247
272
|
const baseUrl = clientConfig.baseUrl || process.env.URL;
|
|
@@ -260,6 +285,7 @@ function convertClientConfig(clientConfig) {
|
|
|
260
285
|
if (clientConfig.projectIntegration) {
|
|
261
286
|
clientConfig.api = Object.assign({ default: true }, clientConfig.api);
|
|
262
287
|
}
|
|
288
|
+
clientConfig.enableStatusPage = Object.assign({ database: true, filesystem: true }, (clientConfig.enableStatusPage || {}));
|
|
263
289
|
return Object.assign(Object.assign({}, clientConfig), { baseUrl: baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl, clientId,
|
|
264
290
|
clientSecret, awsConfig: {
|
|
265
291
|
tmpBucketName,
|
|
@@ -18,8 +18,12 @@ function handle(moduleConfig) {
|
|
|
18
18
|
return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
19
19
|
if (moduleConfig.formSchema) {
|
|
20
20
|
return res.render('form', {
|
|
21
|
-
formGetDataUrl: moduleConfig.formGetDataUrl
|
|
22
|
-
|
|
21
|
+
formGetDataUrl: moduleConfig.formGetDataUrl
|
|
22
|
+
? moduleConfig.formGetDataUrl
|
|
23
|
+
: `/api/${moduleConfig.key}/form-data`,
|
|
24
|
+
formPostDataUrl: moduleConfig.formPostDataUrl
|
|
25
|
+
? moduleConfig.formPostDataUrl
|
|
26
|
+
: `/api/${moduleConfig.key}/form-data`,
|
|
23
27
|
formSchema: JSON.stringify(moduleConfig.formSchema),
|
|
24
28
|
formUiSchema: moduleConfig.formUiSchema ? JSON.stringify(moduleConfig.formUiSchema) : '{}',
|
|
25
29
|
});
|
|
@@ -17,6 +17,7 @@ const util_1 = require("../../../util");
|
|
|
17
17
|
const defaults_1 = require("../util/defaults");
|
|
18
18
|
const logger_1 = require("../../../util/logger");
|
|
19
19
|
const storage_1 = require("../../../storage");
|
|
20
|
+
const crowdin_apps_functions_1 = require("@crowdin/crowdin-apps-functions");
|
|
20
21
|
function handle(config, integration) {
|
|
21
22
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
22
23
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
@@ -28,6 +29,7 @@ function handle(config, integration) {
|
|
|
28
29
|
(0, logger_1.log)(`Received request from OAuth login callback. Code ${code}`);
|
|
29
30
|
(0, logger_1.log)(`Received request from OAuth login callback. State ${state}`);
|
|
30
31
|
const clientId = Buffer.from(state, 'base64').toString();
|
|
32
|
+
const { organization } = (0, crowdin_apps_functions_1.parseCrowdinId)(clientId);
|
|
31
33
|
const redirectUri = `${config.baseUrl}${(0, defaults_1.getOauthRoute)(integration)}`;
|
|
32
34
|
try {
|
|
33
35
|
const oauthLogin = integration.oauthLogin;
|
|
@@ -61,7 +63,7 @@ function handle(config, integration) {
|
|
|
61
63
|
message.data = oauthCredentials;
|
|
62
64
|
if (((_o = integration.oauthLogin) === null || _o === void 0 ? void 0 : _o.mode) === 'polling') {
|
|
63
65
|
yield (0, storage_1.getStorage)().deleteMetadata((0, defaults_1.getOAuthPollingId)(clientId));
|
|
64
|
-
yield (0, storage_1.getStorage)().saveMetadata((0, defaults_1.getOAuthPollingId)(clientId), oauthCredentials);
|
|
66
|
+
yield (0, storage_1.getStorage)().saveMetadata((0, defaults_1.getOAuthPollingId)(clientId), oauthCredentials, organization);
|
|
65
67
|
}
|
|
66
68
|
return res.render('oauth', { message: JSON.stringify(message), oauthMode: (_p = integration.oauthLogin) === null || _p === void 0 ? void 0 : _p.mode });
|
|
67
69
|
}
|
|
@@ -23,7 +23,7 @@ function handle(config, integration) {
|
|
|
23
23
|
}
|
|
24
24
|
const { loginForm } = req.body;
|
|
25
25
|
yield (0, storage_1.getStorage)().deleteMetadata((0, defaults_1.getOAuthLoginFormId)(req.crowdinContext.clientId));
|
|
26
|
-
yield (0, storage_1.getStorage)().saveMetadata((0, defaults_1.getOAuthLoginFormId)(req.crowdinContext.clientId), loginForm);
|
|
26
|
+
yield (0, storage_1.getStorage)().saveMetadata((0, defaults_1.getOAuthLoginFormId)(req.crowdinContext.clientId), loginForm, req.crowdinContext.crowdinId);
|
|
27
27
|
const url = (0, defaults_1.constructOauthUrl)({ config, integration, clientId: req.crowdinContext.clientId, loginForm });
|
|
28
28
|
res.send({ url });
|
|
29
29
|
}));
|
|
@@ -130,7 +130,7 @@ exports.runUpdateProviderJob = runUpdateProviderJob;
|
|
|
130
130
|
function filesCron({ config, integration, period, }) {
|
|
131
131
|
return __awaiter(this, void 0, void 0, function* () {
|
|
132
132
|
(0, logger_1.log)(`Starting files cron job with period [${period}]`);
|
|
133
|
-
const syncSettingsList = yield (0, storage_1.getStorage)().
|
|
133
|
+
const syncSettingsList = yield (0, storage_1.getStorage)().getSyncSettingsBySchedule('schedule', period);
|
|
134
134
|
const crowdinSyncSettings = syncSettingsList.filter((syncSettings) => syncSettings.provider === types_1.Provider.CROWDIN);
|
|
135
135
|
const integrationSyncSettings = syncSettingsList.filter((syncSettings) => syncSettings.provider === types_1.Provider.INTEGRATION);
|
|
136
136
|
yield Promise.all(crowdinSyncSettings.map((syncSettings) => processSyncSettings({ config, integration, period, syncSettings })));
|
package/out/modules/manifest.js
CHANGED
|
@@ -359,7 +359,7 @@ function handle(config) {
|
|
|
359
359
|
const manifest = Object.assign(Object.assign(Object.assign(Object.assign({ identifier: config.identifier, name: config.name, logo: (0, util_1.getLogoUrl)(), baseUrl: config.baseUrl, authentication: {
|
|
360
360
|
type: config.authenticationType || types_1.AuthenticationType.APP,
|
|
361
361
|
clientId: config.clientId,
|
|
362
|
-
} }, (config.agent && { agent: config.agent })), { events, scopes: config.scopes ? config.scopes : defaultScopes }), (config.defaultPermissions && { default_permissions: config.defaultPermissions })), { modules });
|
|
362
|
+
}, restrictAiToSameApp: config.restrictAiToSameApp }, (config.agent && { agent: config.agent })), { events, scopes: config.scopes ? config.scopes : defaultScopes }), (config.defaultPermissions && { default_permissions: config.defaultPermissions })), { modules });
|
|
363
363
|
res.send(manifest);
|
|
364
364
|
};
|
|
365
365
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/// <reference types="qs" />
|
|
2
|
+
import { Request, Response } from 'express';
|
|
3
|
+
import { Config, UnauthorizedConfig } from '../types';
|
|
4
|
+
export default function handle(config: Config | UnauthorizedConfig): (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;
|
|
@@ -0,0 +1,74 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const util_1 = require("../util");
|
|
16
|
+
const logger_1 = require("../util/logger");
|
|
17
|
+
const storage_1 = require("../storage");
|
|
18
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
const os_1 = __importDefault(require("os"));
|
|
21
|
+
function handle(config) {
|
|
22
|
+
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
var _a, _b;
|
|
24
|
+
const response = {
|
|
25
|
+
status: 'ok',
|
|
26
|
+
timestamp: new Date().toISOString(),
|
|
27
|
+
};
|
|
28
|
+
let hasError = false;
|
|
29
|
+
if (((_a = config === null || config === void 0 ? void 0 : config.enableStatusPage) === null || _a === void 0 ? void 0 : _a.database) === true) {
|
|
30
|
+
let status = 'ok';
|
|
31
|
+
let message = 'Database connection successful';
|
|
32
|
+
try {
|
|
33
|
+
yield (0, storage_1.getStorage)().getAllMetadata();
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
status = 'error';
|
|
37
|
+
message = (e === null || e === void 0 ? void 0 : e.message) || 'Database connection error';
|
|
38
|
+
hasError = true;
|
|
39
|
+
(0, logger_1.logError)(e);
|
|
40
|
+
}
|
|
41
|
+
response.database = {
|
|
42
|
+
status,
|
|
43
|
+
message,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (((_b = config === null || config === void 0 ? void 0 : config.enableStatusPage) === null || _b === void 0 ? void 0 : _b.filesystem) === true) {
|
|
47
|
+
let status = 'ok';
|
|
48
|
+
let message = 'Filesystem access successful';
|
|
49
|
+
try {
|
|
50
|
+
const testFile = path_1.default.join(os_1.default.tmpdir(), 'status-check.txt');
|
|
51
|
+
yield promises_1.default.writeFile(testFile, 'test');
|
|
52
|
+
yield promises_1.default.unlink(testFile);
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
status = 'error';
|
|
56
|
+
message = (e === null || e === void 0 ? void 0 : e.message) || 'Filesystem error';
|
|
57
|
+
hasError = true;
|
|
58
|
+
(0, logger_1.logError)(e);
|
|
59
|
+
}
|
|
60
|
+
response.filesystem = {
|
|
61
|
+
status,
|
|
62
|
+
message,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (hasError) {
|
|
66
|
+
response.status = 'error';
|
|
67
|
+
res.status(503).json(response);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
res.json(response);
|
|
71
|
+
}
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
exports.default = handle;
|