@crowdin/app-project-module 1.4.0 → 1.4.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.
@@ -17,11 +17,18 @@ const jsx_renderer_1 = require("../util/jsx-renderer");
17
17
  function handle(moduleConfig, config) {
18
18
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
19
19
  if (moduleConfig.formSchema) {
20
+ // Skip non-HTML requests so custom form data endpoints (formGetDataUrl/formPostDataUrl)
21
+ // are not intercepted when they share the same base path as the module UI route
22
+ if (!/\.html?$/i.test(req.path)) {
23
+ return next();
24
+ }
20
25
  const html = (0, jsx_renderer_1.renderJSXOnServer)(views_1.FormPage, {
21
26
  formGetDataUrl: moduleConfig.formGetDataUrl || `/api/${moduleConfig.key}/form-data`,
22
27
  formPostDataUrl: moduleConfig.formPostDataUrl || `/api/${moduleConfig.key}/form-data`,
23
- formSchema: JSON.stringify(moduleConfig.formSchema),
24
- formUiSchema: moduleConfig.formUiSchema ? JSON.stringify(moduleConfig.formUiSchema) : '{}',
28
+ formSchema: JSON.stringify(moduleConfig.formSchema).replace(/</g, '\\u003c'),
29
+ formUiSchema: moduleConfig.formUiSchema
30
+ ? JSON.stringify(moduleConfig.formUiSchema).replace(/</g, '\\u003c')
31
+ : '{}',
25
32
  formPatchDataUrl: moduleConfig.formPatchDataUrl,
26
33
  });
27
34
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
@@ -166,10 +166,18 @@ function filesCron(_a) {
166
166
  const syncSettingsList = yield (0, storage_1.getStorage)().getSyncSettingsBySchedule('schedule', period);
167
167
  const crowdinSyncSettings = syncSettingsList.filter((syncSettings) => syncSettings.provider === types_1.Provider.CROWDIN);
168
168
  const integrationSyncSettings = syncSettingsList.filter((syncSettings) => syncSettings.provider === types_1.Provider.INTEGRATION);
169
- yield Promise.all(crowdinSyncSettings.map((syncSettings) => processSyncSettings({ config, integration, period, syncSettings })));
170
- yield Promise.all([
171
- integrationSyncSettings.map((syncSettings) => processSyncSettings({ config, integration, period, syncSettings })),
172
- ]);
169
+ const crowdinResults = yield Promise.allSettled(crowdinSyncSettings.map((syncSettings) => processSyncSettings({ config, integration, period, syncSettings })));
170
+ crowdinResults.forEach((result) => {
171
+ if (result.status === 'rejected') {
172
+ (0, logger_1.logError)(result.reason);
173
+ }
174
+ });
175
+ const integrationResults = yield Promise.allSettled(integrationSyncSettings.map((syncSettings) => processSyncSettings({ config, integration, period, syncSettings })));
176
+ integrationResults.forEach((result) => {
177
+ if (result.status === 'rejected') {
178
+ (0, logger_1.logError)(result.reason);
179
+ }
180
+ });
173
181
  (0, logger_1.log)(`Files cron job with period [${period}] completed`);
174
182
  });
175
183
  }
@@ -270,7 +270,7 @@ function prepareIntegrationCredentials(config, integration, integrationCredentia
270
270
  const performRefreshTokenRequest = (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.performRefreshTokenRequest) || (integrationLogin === null || integrationLogin === void 0 ? void 0 : integrationLogin.performRefreshTokenRequest);
271
271
  credentials.tokenProvider = {
272
272
  getToken: (...args_1) => __awaiter(this, [...args_1], void 0, function* (force = false) {
273
- var _a, _b, _c, _d, _e, _f, _g;
273
+ var _a, _b, _c, _d;
274
274
  const { expireIn } = credentials;
275
275
  //2 min as an extra buffer
276
276
  const isExpired = !expireIn || expireIn - 120 < Date.now() / 1000;
@@ -280,33 +280,68 @@ function prepareIntegrationCredentials(config, integration, integrationCredentia
280
280
  (0, logger_1.log)(force
281
281
  ? 'Force refreshing integration credentials'
282
282
  : 'Integration credentials have expired during operation. Requesting a new credentials');
283
+ const doRefresh = (currentCredentials) => __awaiter(this, void 0, void 0, function* () {
284
+ var _a, _b, _c;
285
+ if (performRefreshTokenRequest) {
286
+ const loginForm = yield (0, storage_1.getStorage)().getMetadata((0, defaults_1.getOAuthLoginFormId)(integrationCredentials.id));
287
+ return performRefreshTokenRequest({ credentials: currentCredentials, loginForm });
288
+ }
289
+ else if (oauthLogin) {
290
+ const url = oauthLogin.refreshTokenUrl || oauthLogin.accessTokenUrl;
291
+ const request = {};
292
+ request[((_a = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _a === void 0 ? void 0 : _a.clientId) || 'client_id'] = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.clientId;
293
+ request[((_b = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _b === void 0 ? void 0 : _b.clientSecret) || 'client_secret'] = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.clientSecret;
294
+ request[((_c = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _c === void 0 ? void 0 : _c.refreshToken) || 'refresh_token'] =
295
+ currentCredentials.refreshToken;
296
+ if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.extraRefreshTokenParameters) {
297
+ Object.entries(oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.extraRefreshTokenParameters).forEach(([key, value]) => (request[key] = value));
298
+ }
299
+ return (yield axios_1.default.post(url || '', request, {
300
+ headers: { Accept: 'application/json' },
301
+ })).data;
302
+ }
303
+ return null;
304
+ });
283
305
  let newCredentials;
284
- if (performRefreshTokenRequest) {
285
- const loginForm = yield (0, storage_1.getStorage)().getMetadata((0, defaults_1.getOAuthLoginFormId)(integrationCredentials.id));
286
- newCredentials = yield performRefreshTokenRequest({ credentials, loginForm });
306
+ try {
307
+ newCredentials = yield doRefresh(credentials);
287
308
  }
288
- else if (oauthLogin) {
289
- const url = oauthLogin.refreshTokenUrl || oauthLogin.accessTokenUrl;
290
- const request = {};
291
- request[((_a = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _a === void 0 ? void 0 : _a.clientId) || 'client_id'] = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.clientId;
292
- request[((_b = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _b === void 0 ? void 0 : _b.clientSecret) || 'client_secret'] = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.clientSecret;
293
- request[((_c = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _c === void 0 ? void 0 : _c.refreshToken) || 'refresh_token'] = credentials.refreshToken;
294
- if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.extraRefreshTokenParameters) {
295
- Object.entries(oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.extraRefreshTokenParameters).forEach(([key, value]) => (request[key] = value));
309
+ catch (e) {
310
+ // In-memory refresh token may be stale (rotated by another process/worker,
311
+ // or the token itself expired). Try fetching fresh credentials from DB.
312
+ (0, logger_1.log)('Token refresh failed. Attempting to fetch fresh credentials from the database');
313
+ const freshStoredCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(integrationCredentials.id);
314
+ if (freshStoredCredentials) {
315
+ const freshCredentials = JSON.parse((0, _1.decryptData)(config, freshStoredCredentials.credentials));
316
+ if (freshCredentials.refreshToken &&
317
+ freshCredentials.refreshToken !== credentials.refreshToken) {
318
+ (0, logger_1.log)('Found a newer refresh token in the database, retrying token refresh');
319
+ try {
320
+ newCredentials = yield doRefresh(freshCredentials);
321
+ credentials.refreshToken = freshCredentials.refreshToken;
322
+ }
323
+ catch (retryError) {
324
+ (0, logger_1.logError)(retryError);
325
+ throw retryError;
326
+ }
327
+ }
328
+ else {
329
+ throw e;
330
+ }
331
+ }
332
+ else {
333
+ throw e;
296
334
  }
297
- newCredentials = (yield axios_1.default.post(url || '', request, {
298
- headers: { Accept: 'application/json' },
299
- })).data;
300
335
  }
301
- else {
336
+ if (!newCredentials) {
302
337
  return credentials.accessToken;
303
338
  }
304
- credentials.accessToken = newCredentials[((_d = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _d === void 0 ? void 0 : _d.accessToken) || 'access_token'];
339
+ credentials.accessToken = newCredentials[((_a = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _a === void 0 ? void 0 : _a.accessToken) || 'access_token'];
305
340
  credentials.expireIn =
306
- Number(newCredentials[((_e = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _e === void 0 ? void 0 : _e.expiresIn) || 'expires_in']) + Date.now() / 1000;
307
- if (newCredentials[((_f = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _f === void 0 ? void 0 : _f.refreshToken) || 'refresh_token']) {
341
+ Number(newCredentials[((_b = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _b === void 0 ? void 0 : _b.expiresIn) || 'expires_in']) + Date.now() / 1000;
342
+ if (newCredentials[((_c = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _c === void 0 ? void 0 : _c.refreshToken) || 'refresh_token']) {
308
343
  credentials.refreshToken =
309
- newCredentials[((_g = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _g === void 0 ? void 0 : _g.refreshToken) || 'refresh_token'];
344
+ newCredentials[((_d = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _d === void 0 ? void 0 : _d.refreshToken) || 'refresh_token'];
310
345
  }
311
346
  (0, logger_1.log)('Saving updated integration credentials in the database');
312
347
  yield (0, storage_1.getStorage)().updateIntegrationCredentials(integrationCredentials.id, (0, _1.encryptData)(config, JSON.stringify(credentials)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "1.4.0",
3
+ "version": "1.4.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",