@crowdin/app-project-module 0.36.0 → 0.37.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.
@@ -53,7 +53,6 @@ function catchRejection(e, message) {
53
53
  subscriptionModal.open();
54
54
  return;
55
55
  }
56
- console.error(e.message || message);
57
56
  showToast(e.message || message);
58
57
  }
59
58
 
@@ -1,9 +1,10 @@
1
1
  import Crowdin from '@crowdin/crowdin-api-client';
2
- import { AccountType, Config, CrowdinCredentials, IntegrationCredentials, IntegrationLogic, SubscriptionInfo } from '../models';
3
- export declare function prepareCrowdinClient({ config, credentials, autoRenew, }: {
2
+ import { AccountType, Config, CrowdinContextInfo, CrowdinCredentials, IntegrationCredentials, IntegrationLogic, SubscriptionInfo } from '../models';
3
+ export declare function prepareCrowdinClient({ config, credentials, autoRenew, context, }: {
4
4
  config: Config;
5
5
  credentials: CrowdinCredentials;
6
6
  autoRenew?: boolean;
7
+ context?: CrowdinContextInfo;
7
8
  }): Promise<{
8
9
  client: Crowdin;
9
10
  token: string;
@@ -54,7 +54,7 @@ function refreshToken(config, credentials) {
54
54
  };
55
55
  });
56
56
  }
57
- function prepareCrowdinClient({ config, credentials, autoRenew = false, }) {
57
+ function prepareCrowdinClient({ config, credentials, autoRenew = false, context, }) {
58
58
  var _a, _b;
59
59
  return __awaiter(this, void 0, void 0, function* () {
60
60
  //2 min as an extra buffer
@@ -114,6 +114,7 @@ function prepareCrowdinClient({ config, credentials, autoRenew = false, }) {
114
114
  const res = yield axiosCustom.get(url, getHttpConfig(httpConfig));
115
115
  return res.data;
116
116
  }
117
+ (0, logger_1.logError)(e, context);
117
118
  throw e;
118
119
  }
119
120
  });
@@ -130,6 +131,7 @@ function prepareCrowdinClient({ config, credentials, autoRenew = false, }) {
130
131
  const res = yield axiosCustom.delete(url, getHttpConfig(httpConfig));
131
132
  return res.data;
132
133
  }
134
+ (0, logger_1.logError)(e, context);
133
135
  throw e;
134
136
  }
135
137
  });
@@ -146,6 +148,7 @@ function prepareCrowdinClient({ config, credentials, autoRenew = false, }) {
146
148
  const res = yield axiosCustom.head(url, getHttpConfig(httpConfig));
147
149
  return res.data;
148
150
  }
151
+ (0, logger_1.logError)(e, context);
149
152
  throw e;
150
153
  }
151
154
  });
@@ -162,6 +165,7 @@ function prepareCrowdinClient({ config, credentials, autoRenew = false, }) {
162
165
  const res = yield axiosCustom.patch(url, data, getHttpConfig(httpConfig));
163
166
  return res.data;
164
167
  }
168
+ (0, logger_1.logError)(e, context);
165
169
  throw e;
166
170
  }
167
171
  });
@@ -178,6 +182,7 @@ function prepareCrowdinClient({ config, credentials, autoRenew = false, }) {
178
182
  const res = yield axiosCustom.post(url, data, getHttpConfig(httpConfig));
179
183
  return res.data;
180
184
  }
185
+ (0, logger_1.logError)(e, context);
181
186
  throw e;
182
187
  }
183
188
  });
@@ -194,6 +199,7 @@ function prepareCrowdinClient({ config, credentials, autoRenew = false, }) {
194
199
  const res = yield axiosCustom.put(url, data, getHttpConfig(httpConfig));
195
200
  return res.data;
196
201
  }
202
+ (0, logger_1.logError)(e, context);
197
203
  throw e;
198
204
  }
199
205
  });
package/out/util/cron.js CHANGED
@@ -95,10 +95,23 @@ function filesCron(config, integration, period) {
95
95
  return;
96
96
  }
97
97
  const projectId = crowdinAppFunctions.getProjectId(integrationCredentials.id);
98
+ const context = {
99
+ jwtPayload: {
100
+ context: {
101
+ // eslint-disable-next-line @typescript-eslint/camelcase
102
+ project_id: projectId,
103
+ // eslint-disable-next-line @typescript-eslint/camelcase
104
+ organization_id: crowdinCredentials.organizationId,
105
+ // eslint-disable-next-line @typescript-eslint/camelcase
106
+ user_id: crowdinCredentials.userId,
107
+ },
108
+ },
109
+ };
98
110
  const { client: crowdinClient, token } = yield (0, connection_1.prepareCrowdinClient)({
99
111
  config,
100
112
  credentials: crowdinCredentials,
101
113
  autoRenew: true,
114
+ context,
102
115
  });
103
116
  const { expired } = yield (0, connection_1.checkSubscription)({
104
117
  config,
@@ -159,7 +172,13 @@ function filesCron(config, integration, period) {
159
172
  }
160
173
  }
161
174
  const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
162
- yield integration.updateIntegration(projectId, crowdinClient, apiCredentials, filesToProcess, rootFolder, intConfig);
175
+ try {
176
+ yield integration.updateIntegration(projectId, crowdinClient, apiCredentials, filesToProcess, rootFolder, intConfig);
177
+ }
178
+ catch (e) {
179
+ (0, logger_1.logError)(e, context);
180
+ throw e;
181
+ }
163
182
  if (Object.keys(newFiles).length) {
164
183
  yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(Object.assign(Object.assign({}, files), newFiles)), syncSettings.integrationId, syncSettings.crowdinId, 'schedule', syncSettings.provider);
165
184
  const currentFileSnapshot = yield (0, file_snapshot_1.getCrowdinSnapshot)(config, integration, crowdinClient, projectId, intConfig);
@@ -176,7 +195,13 @@ function filesCron(config, integration, period) {
176
195
  const intFiles = allIntFiles.filter((file) => 'type' in file);
177
196
  (0, logger_1.log)(`Executing updateCrowdin task for files cron job with period [${period}] for project ${projectId}. Files ${intFiles.length}`);
178
197
  const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
179
- yield integration.updateCrowdin(projectId, crowdinClient, apiCredentials, intFiles, rootFolder, intConfig);
198
+ try {
199
+ yield integration.updateCrowdin(projectId, crowdinClient, apiCredentials, intFiles, rootFolder, intConfig);
200
+ }
201
+ catch (e) {
202
+ (0, logger_1.logError)(e, context);
203
+ throw e;
204
+ }
180
205
  if (Object.keys(newFiles).length) {
181
206
  const newSyncSettingsFields = allIntFiles.map((file) => (Object.assign(Object.assign({}, file), { schedule: true, sync: false })));
182
207
  yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(newSyncSettingsFields), syncSettings.integrationId, syncSettings.crowdinId, 'schedule', syncSettings.provider);
@@ -1,3 +1,4 @@
1
+ import { AxiosError } from 'axios';
1
2
  import { Config, CrowdinContextInfo } from '../models';
2
3
  export type LogFunction = (message: string) => void;
3
4
  export type LogErrorFunction = (error: any) => void;
@@ -12,4 +13,18 @@ export declare function withContext(context: CrowdinContextInfo): LogFunction;
12
13
  export declare function withContextError(context: CrowdinContextInfo): LogFunction;
13
14
  export declare function log(message: string, context?: CrowdinContextInfo): void;
14
15
  export declare function logError(e: any, context?: CrowdinContextInfo): void;
16
+ export declare function isAxiosError(e: any): e is CustomAxiosError;
15
17
  export declare function getErrorMessage(err: any): any;
18
+ interface CustomAxiosError extends AxiosError {
19
+ data?: any;
20
+ }
21
+ export declare class AppModuleError extends Error {
22
+ data: any;
23
+ isAxiosError: boolean;
24
+ constructor(error: CustomAxiosError | Error | string, data?: any);
25
+ }
26
+ export declare class AppModuleAggregateError extends Error {
27
+ errors: Error[] | AppModuleError[];
28
+ constructor(errors: Error[] | AppModuleError[], message: string);
29
+ }
30
+ export {};
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.getErrorMessage = exports.logError = exports.log = exports.withContextError = exports.withContext = exports.prepareContext = exports.initialize = void 0;
26
+ exports.AppModuleAggregateError = exports.AppModuleError = exports.getErrorMessage = exports.isAxiosError = exports.logError = exports.log = exports.withContextError = exports.withContext = exports.prepareContext = exports.initialize = void 0;
27
27
  const logsFormatter = __importStar(require("@crowdin/logs-formatter"));
28
28
  let logConfig;
29
29
  let onError;
@@ -78,7 +78,6 @@ function logError(e, context) {
78
78
  onError(e, context);
79
79
  }
80
80
  else {
81
- let message = `[${new Date().toISOString()}] Error.`;
82
81
  if (context) {
83
82
  logsFormatter.setContext({
84
83
  project: {
@@ -89,22 +88,47 @@ function logError(e, context) {
89
88
  user_id: context.jwtPayload.context.user_id,
90
89
  },
91
90
  });
92
- message += ` Context ${JSON.stringify(prepareContext(context))}`;
93
91
  }
94
- if (isAxiosError(e)) {
95
- const request = e.config ? { url: e.config.url, method: e.config.method, data: e.config.data } : {};
96
- const response = e.response ? { data: e.response.data, status: e.response.status } : {};
97
- console.error(`${message} Axios error. Request ${JSON.stringify(request)}. Response ${JSON.stringify(response)}. Message ${e.message}`);
92
+ if (e instanceof AppModuleAggregateError) {
93
+ if (e.errors && e.errors.length > 0) {
94
+ for (const error of e.errors) {
95
+ errorOutputByType(error);
96
+ }
97
+ }
98
98
  }
99
99
  else {
100
- console.error(message, e);
100
+ errorOutputByType(e);
101
101
  }
102
102
  }
103
103
  }
104
104
  exports.logError = logError;
105
+ function errorOutputByType(error) {
106
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
107
+ const message = error.message || error;
108
+ if (isAxiosError(error)) {
109
+ const request = error.config || error.data.config
110
+ ? {
111
+ url: ((_a = error.config) === null || _a === void 0 ? void 0 : _a.url) || ((_b = error.data) === null || _b === void 0 ? void 0 : _b.config.url),
112
+ method: ((_c = error.config) === null || _c === void 0 ? void 0 : _c.method) || ((_d = error.data) === null || _d === void 0 ? void 0 : _d.config.method),
113
+ data: ((_e = error.config) === null || _e === void 0 ? void 0 : _e.data) || ((_f = error.data) === null || _f === void 0 ? void 0 : _f.config.data),
114
+ }
115
+ : {};
116
+ const response = error.response || error.data.response
117
+ ? {
118
+ data: ((_g = error.response) === null || _g === void 0 ? void 0 : _g.data) || ((_h = error.data) === null || _h === void 0 ? void 0 : _h.response.data),
119
+ status: ((_j = error.response) === null || _j === void 0 ? void 0 : _j.status) || ((_k = error.data) === null || _k === void 0 ? void 0 : _k.response.status),
120
+ }
121
+ : {};
122
+ console.error(message, { attributes: { request, response } }, { backtrace: error.stack });
123
+ }
124
+ else {
125
+ console.error(message, error.data ? { attributes: error.data } : '', error.stack ? { backtrace: error.stack } : '');
126
+ }
127
+ }
105
128
  function isAxiosError(e) {
106
129
  return !!e.isAxiosError;
107
130
  }
131
+ exports.isAxiosError = isAxiosError;
108
132
  function getErrorMessage(err) {
109
133
  let message;
110
134
  if (typeof err === 'string') {
@@ -119,3 +143,24 @@ function getErrorMessage(err) {
119
143
  return message;
120
144
  }
121
145
  exports.getErrorMessage = getErrorMessage;
146
+ class AppModuleError extends Error {
147
+ constructor(error, data) {
148
+ super(typeof error === 'string' ? error : error.message);
149
+ this.isAxiosError = false;
150
+ this.name = 'AppModuleError';
151
+ this.data = typeof error === 'string' ? Object.assign({}, data) : Object.assign(Object.assign({}, error), data);
152
+ this.stack = typeof error === 'string' ? this.stack : error.stack;
153
+ if (isAxiosError(error)) {
154
+ this.isAxiosError = true;
155
+ }
156
+ }
157
+ }
158
+ exports.AppModuleError = AppModuleError;
159
+ class AppModuleAggregateError extends Error {
160
+ constructor(errors, message) {
161
+ super(message);
162
+ this.name = 'AppModuleAggregateError';
163
+ this.errors = errors;
164
+ }
165
+ }
166
+ exports.AppModuleAggregateError = AppModuleAggregateError;
@@ -91,7 +91,7 @@ function registerWebhooks(config, integration, client, crowdinContext, apiCreden
91
91
  const webhookName = `${config.name} application hook ${crowdinContext.jwtPayload.sub}`;
92
92
  const webhookUrl = makeCrowdinWebhookUrl(config, integration, crowdinContext);
93
93
  const syncCondition = models_1.SyncCondition[Number(appSettings.condition)];
94
- const events = HookConditionEvents[syncCondition];
94
+ const events = [...HookConditionEvents[syncCondition]];
95
95
  const webhook = yield getCrowdinProjectWebhook(config, client, projectId, webhookName);
96
96
  if (appSettings['new-crowdin-files']) {
97
97
  events.push(exports.HookEvents.fileAdded);
@@ -226,8 +226,24 @@ function prepareWebhookData(config, integration, webhookUrlParam, provider) {
226
226
  let appSettings = {};
227
227
  const { projectId, crowdinId, clientId } = decodedUrlParam(config, webhookUrlParam);
228
228
  const crowdinCredentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(crowdinId);
229
- const crowdinClient = yield (0, connection_1.prepareCrowdinClient)({ config, credentials: crowdinCredentials });
230
229
  const integrationCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(clientId);
230
+ const context = {
231
+ jwtPayload: {
232
+ context: {
233
+ // eslint-disable-next-line @typescript-eslint/camelcase
234
+ project_id: projectId,
235
+ // eslint-disable-next-line @typescript-eslint/camelcase
236
+ organization_id: crowdinCredentials === null || crowdinCredentials === void 0 ? void 0 : crowdinCredentials.organizationId,
237
+ // eslint-disable-next-line @typescript-eslint/camelcase
238
+ user_id: crowdinCredentials === null || crowdinCredentials === void 0 ? void 0 : crowdinCredentials.userId,
239
+ },
240
+ },
241
+ };
242
+ const crowdinClient = yield (0, connection_1.prepareCrowdinClient)({
243
+ config,
244
+ credentials: crowdinCredentials,
245
+ context,
246
+ });
231
247
  const preparedIntegrationCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
232
248
  if (integrationCredentials === null || integrationCredentials === void 0 ? void 0 : integrationCredentials.config) {
233
249
  appSettings = JSON.parse(integrationCredentials.config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.36.0",
3
+ "version": "0.37.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",
@@ -17,7 +17,7 @@
17
17
  "@aws-sdk/client-s3": "^3.423.0",
18
18
  "@aws-sdk/s3-request-presigner": "^3.423.0",
19
19
  "@crowdin/crowdin-apps-functions": "0.5.1",
20
- "@crowdin/logs-formatter": "^2.0.3",
20
+ "@crowdin/logs-formatter": "^2.0.4",
21
21
  "@godaddy/terminus": "^4.12.1",
22
22
  "@types/pg": "^8.10.3",
23
23
  "amqplib": "^0.10.3",