@crowdin/app-project-module 0.68.1 → 0.69.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 CHANGED
@@ -79,6 +79,7 @@ const projectMenuApp = __importStar(require("./modules/project-menu"));
79
79
  const projectMenuCrowdsourceApp = __importStar(require("./modules/project-menu-crowdsource"));
80
80
  const projectReportsApp = __importStar(require("./modules/project-reports"));
81
81
  const projectToolsApp = __importStar(require("./modules/project-tools"));
82
+ const webhooks = __importStar(require("./modules/webhooks"));
82
83
  const subscription_1 = require("./util/subscription");
83
84
  var types_2 = require("./types");
84
85
  Object.defineProperty(exports, "ProjectPermissions", { enumerable: true, get: function () { return types_2.ProjectPermissions; } });
@@ -175,6 +176,7 @@ function addCrowdinEndpoints(app, clientConfig) {
175
176
  aiTools.registerAiTools({ config, app });
176
177
  aiTools.registerAiToolWidgets({ config, app });
177
178
  externalQaCheck.register({ config, app });
179
+ webhooks.register({ config, app });
178
180
  addFormSchema({ config, app });
179
181
  return Object.assign(Object.assign({}, exports.metadataStore), { establishCrowdinConnection: (authRequest, moduleKey) => {
180
182
  let jwtToken = '';
@@ -240,6 +242,9 @@ function convertClientConfig(clientConfig) {
240
242
  throw new Error('Missing [clientId, clientSecret] parameters');
241
243
  }
242
244
  }
245
+ if (clientConfig.projectIntegration) {
246
+ clientConfig.api = Object.assign({ default: true }, clientConfig.api);
247
+ }
243
248
  return Object.assign(Object.assign({}, clientConfig), { baseUrl: baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl, clientId,
244
249
  clientSecret, awsConfig: {
245
250
  tmpBucketName,
@@ -462,7 +462,7 @@ function addDefaultApiEndpoints(app, config) {
462
462
  }
463
463
  exports.addDefaultApiEndpoints = addDefaultApiEndpoints;
464
464
  function addSwagerApiDocumentation(app, config) {
465
- var _a, _b;
465
+ var _a, _b, _c;
466
466
  const options = {
467
467
  swaggerDefinition: {
468
468
  openapi: '3.0.0',
@@ -492,16 +492,16 @@ function addSwagerApiDocumentation(app, config) {
492
492
  },
493
493
  ],
494
494
  },
495
- apis: config.projectIntegration
495
+ apis: config.projectIntegration && ((_a = config.api) === null || _a === void 0 ? void 0 : _a.default)
496
496
  ? [path_1.default.resolve(__dirname, './base.js'), path_1.default.resolve(__dirname, './components.js'), __filename]
497
497
  : [],
498
498
  };
499
- if ((_a = config.api) === null || _a === void 0 ? void 0 : _a.docFile) {
499
+ if ((_b = config.api) === null || _b === void 0 ? void 0 : _b.docFile) {
500
500
  options.apis.push(config.api.docFile);
501
501
  }
502
502
  const swaggerSpec = (0, swagger_jsdoc_1.default)(options);
503
503
  // remove Login info from doc
504
- if (config.projectIntegration && !((_b = config.projectIntegration) === null || _b === void 0 ? void 0 : _b.loginForm)) {
504
+ if (config.projectIntegration && !((_c = config.projectIntegration) === null || _c === void 0 ? void 0 : _c.loginForm)) {
505
505
  delete swaggerSpec.paths['/login'];
506
506
  delete swaggerSpec.paths['/login-fields'];
507
507
  delete swaggerSpec.components.schemas['Login'];
@@ -175,6 +175,8 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
175
175
  user_id: crowdinCredentials.userId,
176
176
  },
177
177
  },
178
+ crowdinId: crowdinCredentials.id,
179
+ clientId: integrationCredentials.id,
178
180
  };
179
181
  try {
180
182
  const preparedCrowdinClient = yield (0, connection_1.prepareCrowdinClient)({
@@ -187,7 +189,7 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
187
189
  crowdinClient = preparedCrowdinClient.client;
188
190
  }
189
191
  catch (e) {
190
- (0, logger_1.logError)(e);
192
+ (0, logger_1.logError)(e, context);
191
193
  return;
192
194
  }
193
195
  const { expired } = yield (0, subscription_1.checkSubscription)({
@@ -205,7 +207,7 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
205
207
  .data;
206
208
  }
207
209
  catch (e) {
208
- (0, logger_1.logError)(e);
210
+ (0, logger_1.logError)(e, context);
209
211
  return;
210
212
  }
211
213
  // eslint-disable-next-line @typescript-eslint/camelcase
@@ -229,7 +231,7 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
229
231
  });
230
232
  }
231
233
  catch (e) {
232
- (0, logger_1.logError)(e);
234
+ (0, logger_1.logError)(e, context);
233
235
  return;
234
236
  }
235
237
  }
@@ -268,6 +270,7 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
268
270
  crowdinClient,
269
271
  onlyApproved,
270
272
  onlyTranslated,
273
+ context,
271
274
  });
272
275
  if (Object.keys(filesToProcess).length <= 0) {
273
276
  return;
@@ -410,7 +413,7 @@ function getNewFoldersFile(folders, snapshotFiles) {
410
413
  files = files.filter((file) => 'type' in file);
411
414
  return files;
412
415
  }
413
- function getOnlyTranslatedOrApprovedFiles({ projectId, crowdinFiles, crowdinClient, onlyApproved, onlyTranslated, }) {
416
+ function getOnlyTranslatedOrApprovedFiles({ projectId, crowdinFiles, crowdinClient, onlyApproved, onlyTranslated, context, }) {
414
417
  return __awaiter(this, void 0, void 0, function* () {
415
418
  (0, logger_1.log)(`Filtering files to process only ${onlyApproved ? 'approved' : 'translated'} files`);
416
419
  const filesInfo = yield Promise.all(Object.keys(crowdinFiles).map((fileId) => __awaiter(this, void 0, void 0, function* () {
@@ -425,7 +428,7 @@ function getOnlyTranslatedOrApprovedFiles({ projectId, crowdinFiles, crowdinClie
425
428
  }
426
429
  catch (e) {
427
430
  delete crowdinFiles[fileId];
428
- (0, logger_1.logError)(e);
431
+ (0, logger_1.logError)(e, context);
429
432
  }
430
433
  })));
431
434
  const filteredFiles = {};
@@ -36,6 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
38
  exports.listenQueueMessage = exports.updateCrowdinFromWebhookRequest = exports.prepareWebhookData = exports.unregisterAllCrowdinWebhooks = exports.unregisterWebhooks = exports.registerWebhooks = exports.HookEvents = void 0;
39
+ const logsFormatter = __importStar(require("@crowdin/logs-formatter"));
39
40
  const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
40
41
  const amqplib_1 = __importDefault(require("amqplib"));
41
42
  const types_1 = require("../types");
@@ -265,8 +266,7 @@ function prepareWebhookData({ config, integration, provider, webhookUrlParam, })
265
266
  if (!crowdinCredentials) {
266
267
  return { projectId, crowdinClient, rootFolder, appSettings, syncSettings, preparedIntegrationCredentials };
267
268
  }
268
- const context = {
269
- jwtPayload: {
269
+ const context = Object.assign({ jwtPayload: {
270
270
  context: {
271
271
  // eslint-disable-next-line @typescript-eslint/camelcase
272
272
  project_id: projectId,
@@ -275,8 +275,9 @@ function prepareWebhookData({ config, integration, provider, webhookUrlParam, })
275
275
  // eslint-disable-next-line @typescript-eslint/camelcase
276
276
  user_id: crowdinCredentials === null || crowdinCredentials === void 0 ? void 0 : crowdinCredentials.userId,
277
277
  },
278
- },
279
- };
278
+ }, crowdinId: crowdinCredentials.id }, ((integrationCredentials === null || integrationCredentials === void 0 ? void 0 : integrationCredentials.id) && { clientId: integrationCredentials.id }));
279
+ logsFormatter.resetContext();
280
+ logsFormatter.setContext(context);
280
281
  crowdinClient = yield (0, connection_1.prepareCrowdinClient)({
281
282
  config,
282
283
  credentials: crowdinCredentials,
@@ -225,6 +225,18 @@ function handle(config) {
225
225
  })));
226
226
  }
227
227
  }
228
+ if (config.webhooks) {
229
+ const webhooks = Array.isArray(config.webhooks) ? config.webhooks : [config.webhooks];
230
+ modules['webhook'] = [];
231
+ for (let i = 0; i < webhooks.length; i++) {
232
+ webhooks[i].key = config.identifier + '-' + 'webhook-' + i;
233
+ modules['webhook'].push({
234
+ key: webhooks[i].key,
235
+ url: '/webhooks',
236
+ events: webhooks[i].events,
237
+ });
238
+ }
239
+ }
228
240
  if (config.externalQaCheck) {
229
241
  config.externalQaCheck.key = config.identifier + '-qa-check';
230
242
  const uiModule = config.externalQaCheck.settingsUiModule;
@@ -0,0 +1,5 @@
1
+ /// <reference types="qs" />
2
+ import { CrowdinClientRequest } from '../../../types';
3
+ import { Response } from 'express';
4
+ import { Webhook } from '../types';
5
+ export declare function webhookHandler(webhooks: Webhook[]): (req: CrowdinClientRequest | import("express").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,75 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.webhookHandler = void 0;
39
+ const util_1 = require("../../../util");
40
+ const lodash_isstring_1 = __importDefault(require("lodash.isstring"));
41
+ const crypto = __importStar(require("node:crypto"));
42
+ const storage = __importStar(require("../../../storage"));
43
+ function webhookHandler(webhooks) {
44
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
45
+ const domain = req.headers['x-crowdin-domain'];
46
+ const organizationId = req.headers['x-crowdin-organization-id'];
47
+ const signature = req.headers['x-crowdin-signature'];
48
+ const moduleKey = req.headers['x-application-webhook-key'];
49
+ if (!(0, lodash_isstring_1.default)(domain) || !(0, lodash_isstring_1.default)(organizationId) || !(0, lodash_isstring_1.default)(signature) || !(0, lodash_isstring_1.default)(moduleKey)) {
50
+ res.status(400).send({ error: 'Invalid request' });
51
+ return;
52
+ }
53
+ const crowdinId = domain || organizationId;
54
+ const credentials = yield storage.getStorage().getCrowdinCredentials(crowdinId);
55
+ if (!credentials) {
56
+ throw new Error('Failed to find Crowdin credentials');
57
+ }
58
+ const hmac = crypto.createHmac('sha256', credentials.appSecret);
59
+ hmac.update(JSON.stringify(req.body).replace(/\//g, '\\/'));
60
+ const generatedSignature = hmac.digest('hex');
61
+ if (generatedSignature !== signature.replace('sha256=', '')) {
62
+ res.status(403).send({ error: 'Invalid signature' });
63
+ return;
64
+ }
65
+ res.status(200).send();
66
+ for (const webhook of webhooks) {
67
+ if (webhook.key === moduleKey) {
68
+ for (const event of req.body.payload.events) {
69
+ yield webhook.callback({ credentials, event });
70
+ }
71
+ }
72
+ }
73
+ }));
74
+ }
75
+ exports.webhookHandler = webhookHandler;
@@ -0,0 +1,6 @@
1
+ import { Config } from '../../types';
2
+ import { Express } from 'express';
3
+ export declare function register({ config, app }: {
4
+ config: Config;
5
+ app: Express;
6
+ }): void;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.register = void 0;
7
+ const json_response_1 = __importDefault(require("../../middlewares/json-response"));
8
+ const webhook_handler_1 = require("./handlers/webhook-handler");
9
+ function register({ config, app }) {
10
+ if (!config.webhooks) {
11
+ return;
12
+ }
13
+ const webhooks = Array.isArray(config.webhooks) ? config.webhooks : [config.webhooks];
14
+ if (webhooks.length) {
15
+ app.post('/webhooks', json_response_1.default, (0, webhook_handler_1.webhookHandler)(webhooks));
16
+ }
17
+ }
18
+ exports.register = register;
@@ -0,0 +1,292 @@
1
+ import { CrowdinCredentials, ModuleKey } from '../../types';
2
+ export interface Webhook extends ModuleKey {
3
+ /**
4
+ * Events that the webhook should listen to
5
+ */
6
+ events: string[];
7
+ /**
8
+ * handle function
9
+ */
10
+ callback: (data: {
11
+ credentials: CrowdinCredentials;
12
+ event: Event;
13
+ }) => Promise<void>;
14
+ }
15
+ interface EventPayload {
16
+ event: string;
17
+ }
18
+ interface BranchPayload {
19
+ id: number;
20
+ }
21
+ interface FilePayload {
22
+ id: number;
23
+ name: string;
24
+ title: string | null;
25
+ type: string;
26
+ path: string;
27
+ status: string;
28
+ revision: number;
29
+ branchId: number | null;
30
+ directoryId: number | null;
31
+ project?: ProjectPayload;
32
+ }
33
+ interface GroupPayload {
34
+ id: number;
35
+ name: string;
36
+ createdAt: string;
37
+ updatedAt: string;
38
+ description: string | null;
39
+ parentId: number;
40
+ userId: number;
41
+ organizationId: number;
42
+ }
43
+ interface LanguagePayload {
44
+ id: string;
45
+ name: string;
46
+ editorCode: string;
47
+ twoLettersCode: string;
48
+ threeLettersCode: string;
49
+ locale: string;
50
+ androidCode: string;
51
+ osxCode: string;
52
+ osxLocale: string;
53
+ textDirection: string;
54
+ dialectOf: string;
55
+ }
56
+ interface ProjectBuildPayload {
57
+ id: number;
58
+ downloadUrl: string;
59
+ project: ProjectPayload;
60
+ }
61
+ interface ProjectPayload {
62
+ id: number;
63
+ userId: number;
64
+ sourceLanguageId: string;
65
+ targetLanguageIds: string[];
66
+ identifier: string;
67
+ name: string;
68
+ createdAt: string;
69
+ updatedAt: string;
70
+ lastActivity: string;
71
+ description: string;
72
+ url: string;
73
+ cname: string | null;
74
+ languageAccessPolicy?: string;
75
+ visibility?: string;
76
+ publicDownloads?: boolean;
77
+ logo?: string;
78
+ isExternal?: boolean;
79
+ externalType?: string | null;
80
+ hasCrowdsourcing?: boolean;
81
+ }
82
+ interface StepPayload {
83
+ name: string;
84
+ }
85
+ interface SuggestionPayload {
86
+ id: number;
87
+ text: string;
88
+ pluralCategoryName: string | null;
89
+ rating: number;
90
+ provider: string | null;
91
+ isPreTranslated: boolean;
92
+ createdAt: string;
93
+ step?: StepPayload | null;
94
+ }
95
+ interface NewSuggestionPayload {
96
+ user: UserPayload | null;
97
+ targetLanguage: LanguagePayload | null;
98
+ string: TranslationPayload | null;
99
+ }
100
+ interface TaskPayload {
101
+ id: number;
102
+ type: number;
103
+ vendor?: string | null;
104
+ status?: string | null;
105
+ title: string;
106
+ assignees: TaskAssigneeUserPayload[];
107
+ assignedTeams: TaskAssigneeTeamPayload[];
108
+ fileIds?: number[];
109
+ branchIds?: number[];
110
+ progress: {
111
+ total: number;
112
+ done: number;
113
+ percent: number;
114
+ };
115
+ description: string;
116
+ translationUrl: string | null;
117
+ wordsCount: number;
118
+ filesCount?: number;
119
+ commentsCount: number;
120
+ deadline: string;
121
+ timeRange: string | null;
122
+ workflowStepId: number;
123
+ buyUrl: string;
124
+ createdAt: string;
125
+ updatedAt: string;
126
+ oldStatus: string | null;
127
+ newStatus: string | null;
128
+ sourceLanguage: LanguagePayload;
129
+ targetLanguage: LanguagePayload | null;
130
+ project: ProjectPayload;
131
+ taskCreator: UserPayload;
132
+ }
133
+ interface TranslationDiscussionsPayload {
134
+ id: number;
135
+ text: string;
136
+ type: string;
137
+ issueType: string;
138
+ issueStatus: string;
139
+ resolvedAt: string;
140
+ createdAt: string;
141
+ string: TranslationPayload;
142
+ targetLanguage: LanguagePayload;
143
+ user: UserPayload;
144
+ commentResolver: UserPayload;
145
+ }
146
+ interface TranslationPayload {
147
+ id: number;
148
+ identifier: string;
149
+ key: string;
150
+ text: string;
151
+ type: string;
152
+ context: string;
153
+ maxLength: number;
154
+ isHidden: boolean;
155
+ isDuplicate: boolean;
156
+ masterStringId: number;
157
+ revision?: number;
158
+ hasPlurals: boolean;
159
+ labelIds: number[];
160
+ url: string;
161
+ createdAt: string;
162
+ updatedAt: string;
163
+ file?: FilePayload;
164
+ branch?: BranchPayload;
165
+ project: ProjectPayload;
166
+ }
167
+ interface UserPayload {
168
+ id: number;
169
+ username: string;
170
+ fullName: string;
171
+ avatarUrl: string;
172
+ }
173
+ interface TaskAssigneeUserPayload extends UserPayload {
174
+ worksCount: number;
175
+ wordsLeft: number;
176
+ }
177
+ interface TaskAssigneeTeamPayload {
178
+ id: number;
179
+ wordsCount: number;
180
+ }
181
+ export interface FileTranslatedEvent extends EventPayload {
182
+ file: FilePayload;
183
+ targetLanguage: LanguagePayload;
184
+ step?: StepPayload;
185
+ }
186
+ export interface FileApprovedEvent extends EventPayload {
187
+ file: FilePayload;
188
+ targetLanguage: LanguagePayload;
189
+ step?: StepPayload;
190
+ }
191
+ export interface FileAddedEvent extends EventPayload {
192
+ file: FilePayload;
193
+ user: UserPayload;
194
+ }
195
+ export interface FileUpdatedEvent extends EventPayload {
196
+ file: FilePayload;
197
+ user: UserPayload;
198
+ }
199
+ export interface FileRevertedEvent extends EventPayload {
200
+ file: FilePayload;
201
+ user: UserPayload;
202
+ }
203
+ export interface FileDeletedEvent extends EventPayload {
204
+ file: FilePayload;
205
+ user: UserPayload;
206
+ }
207
+ export interface ProjectTranslatedEvent extends EventPayload {
208
+ project: ProjectPayload;
209
+ targetLanguage: LanguagePayload;
210
+ workflowStep: StepPayload;
211
+ }
212
+ export interface ProjectApprovedEvent extends EventPayload {
213
+ project: ProjectPayload;
214
+ targetLanguage: LanguagePayload;
215
+ workflowStep: StepPayload;
216
+ }
217
+ export interface ProjectBuiltEvent extends EventPayload {
218
+ build: ProjectBuildPayload;
219
+ }
220
+ export interface TopSuggestionUpdatedEvent extends EventPayload {
221
+ oldTranslation: SuggestionPayload;
222
+ newTranslation: NewSuggestionPayload;
223
+ }
224
+ export interface SuggestionAddedEvent extends EventPayload {
225
+ translation: TranslationPayload;
226
+ }
227
+ export interface SuggestionUpdatedEvent extends EventPayload {
228
+ translation: TranslationPayload;
229
+ }
230
+ export interface SuggestionDeletedEvent extends EventPayload {
231
+ translation: TranslationPayload;
232
+ }
233
+ export interface SuggestionApprovedEvent extends EventPayload {
234
+ translation: TranslationPayload;
235
+ }
236
+ export interface SuggestionDisapprovedEvent extends EventPayload {
237
+ translation: TranslationPayload;
238
+ }
239
+ export interface StringAddedEvent extends EventPayload {
240
+ string: TranslationPayload;
241
+ user: UserPayload;
242
+ }
243
+ export interface StringUpdatedEvent extends EventPayload {
244
+ string: TranslationPayload;
245
+ user: UserPayload;
246
+ }
247
+ export interface StringDeletedEvent extends EventPayload {
248
+ string: TranslationPayload;
249
+ user: UserPayload;
250
+ }
251
+ export interface TranslationDiscussionsCreatedEvent extends EventPayload {
252
+ comment: TranslationDiscussionsPayload;
253
+ }
254
+ export interface TranslationDiscussionsUpdatedEvent extends EventPayload {
255
+ comment: TranslationDiscussionsPayload;
256
+ }
257
+ export interface TranslationDiscussionsDeletedEvent extends EventPayload {
258
+ comment: TranslationDiscussionsPayload;
259
+ }
260
+ export interface TranslationDiscussionsRestoredEvent extends EventPayload {
261
+ comment: TranslationDiscussionsPayload;
262
+ }
263
+ export interface TaskAddedEvent extends EventPayload {
264
+ task: TaskPayload;
265
+ }
266
+ export interface TaskStatusChangedEvent extends EventPayload {
267
+ task: TaskPayload;
268
+ }
269
+ export interface TaskDeletedEvent extends EventPayload {
270
+ task: TaskPayload;
271
+ }
272
+ export interface TaskUpdatedEvent extends EventPayload {
273
+ task: TaskPayload;
274
+ }
275
+ export interface ProjectCreatedEvent extends EventPayload {
276
+ project: ProjectPayload;
277
+ user: UserPayload;
278
+ }
279
+ export interface ProjectDeletedEvent extends EventPayload {
280
+ project: ProjectPayload;
281
+ user: UserPayload;
282
+ }
283
+ export interface GroupCreatedEvent extends EventPayload {
284
+ group: GroupPayload;
285
+ user: UserPayload;
286
+ }
287
+ export interface GroupDeletedEvent extends EventPayload {
288
+ group: GroupPayload;
289
+ user: UserPayload;
290
+ }
291
+ export type Event = FileTranslatedEvent | FileApprovedEvent | FileAddedEvent | FileUpdatedEvent | FileRevertedEvent | FileDeletedEvent | ProjectTranslatedEvent | ProjectApprovedEvent | ProjectBuiltEvent | TopSuggestionUpdatedEvent | SuggestionAddedEvent | SuggestionUpdatedEvent | SuggestionDeletedEvent | SuggestionApprovedEvent | SuggestionDisapprovedEvent | StringAddedEvent | StringUpdatedEvent | StringDeletedEvent | TranslationDiscussionsCreatedEvent | TranslationDiscussionsUpdatedEvent | TranslationDiscussionsDeletedEvent | TranslationDiscussionsRestoredEvent | TaskAddedEvent | TaskStatusChangedEvent | TaskDeletedEvent | TaskUpdatedEvent | ProjectCreatedEvent | ProjectDeletedEvent | GroupCreatedEvent | GroupDeletedEvent;
292
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });