@crowdin/app-project-module 0.29.4 → 0.30.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.
@@ -1,4 +1,4 @@
1
- import { Config, CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, Provider } from '../models';
1
+ import { Config, CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncedFiles, IntegrationSyncSettings, Provider } from '../models';
2
2
  export interface Storage {
3
3
  migrate(): Promise<void>;
4
4
  saveCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
@@ -25,6 +25,9 @@ export interface Storage {
25
25
  saveFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: Provider): Promise<void>;
26
26
  updateFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: Provider): Promise<void>;
27
27
  getFilesSnapshot(integrationId: string, crowdinId: string, provider: Provider): Promise<IntegrationFilesSnapshot | undefined>;
28
+ saveSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
29
+ updateSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
30
+ getSyncedFiles(integrationId: string, crowdinId: string): Promise<IntegrationSyncedFiles | undefined>;
28
31
  }
29
32
  export declare function initialize(config: Config): Promise<void>;
30
33
  export declare function getStorage(): Storage;
@@ -1,5 +1,5 @@
1
1
  import { Storage } from '.';
2
- import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings } from '../models';
2
+ import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncedFiles, IntegrationSyncSettings } from '../models';
3
3
  export interface MySQLStorageConfig {
4
4
  uri?: string;
5
5
  host?: string;
@@ -42,4 +42,7 @@ export declare class MySQLStorage implements Storage {
42
42
  saveFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
43
43
  updateFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
44
44
  getFilesSnapshot(integrationId: string, crowdinId: string, provider: string): Promise<IntegrationFilesSnapshot | undefined>;
45
+ saveSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
46
+ updateSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
47
+ getSyncedFiles(integrationId: string, crowdinId: string): Promise<IntegrationSyncedFiles | undefined>;
45
48
  }
@@ -114,6 +114,15 @@ class MySQLStorage {
114
114
  provider varchar(255) not null
115
115
  )
116
116
  `);
117
+ yield connection.execute(`
118
+ create table if not exists synced_files
119
+ (
120
+ id int auto_increment primary key,
121
+ integration_id varchar(255) not null,
122
+ crowdin_id varchar(255) not null,
123
+ file_ids text
124
+ )
125
+ `);
117
126
  });
118
127
  }
119
128
  saveCrowdinCredentials(credentials) {
@@ -297,7 +306,7 @@ class MySQLStorage {
297
306
  saveSyncSettings(files, integrationId, crowdinId, type, provider) {
298
307
  return __awaiter(this, void 0, void 0, function* () {
299
308
  yield this.dbPromise;
300
- yield this.executeQuery((connection) => connection.execute('INSERT INTO sync_settings(files, integration_id, crowdin_id, type, provider) VALUES (?, , ?, ?, ?)', [files, integrationId, crowdinId, type, provider]));
309
+ yield this.executeQuery((connection) => connection.execute('INSERT INTO sync_settings(files, integration_id, crowdin_id, type, provider) VALUES (?, ?, ?, ?, ?)', [files, integrationId, crowdinId, type, provider]));
301
310
  });
302
311
  }
303
312
  updateSyncSettings(files, integrationId, crowdinId, type, provider) {
@@ -336,5 +345,34 @@ class MySQLStorage {
336
345
  }));
337
346
  });
338
347
  }
348
+ saveSyncedFiles(fileIds, integrationId, crowdinId) {
349
+ return __awaiter(this, void 0, void 0, function* () {
350
+ yield this.dbPromise;
351
+ yield this.executeQuery((connection) => connection.execute('INSERT INTO synced_files(file_ids, integration_id, crowdin_id) VALUES (?, ?, ?)', [
352
+ fileIds,
353
+ integrationId,
354
+ crowdinId,
355
+ ]));
356
+ });
357
+ }
358
+ updateSyncedFiles(fileIds, integrationId, crowdinId) {
359
+ return __awaiter(this, void 0, void 0, function* () {
360
+ yield this.dbPromise;
361
+ yield this.executeQuery((connection) => connection.execute('UPDATE synced_files SET file_ids = ? WHERE integration_id = ? AND crowdin_id = ?', [
362
+ fileIds,
363
+ integrationId,
364
+ crowdinId,
365
+ ]));
366
+ });
367
+ }
368
+ getSyncedFiles(integrationId, crowdinId) {
369
+ return __awaiter(this, void 0, void 0, function* () {
370
+ yield this.dbPromise;
371
+ return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
372
+ const [rows] = yield connection.execute('SELECT id, file_ids as "fileIds", integration_id as "integrationId", crowdin_id as "crowdinId" FROM synced_files WHERE integration_id = ? AND crowdin_id = ?', [integrationId, crowdinId]);
373
+ return (rows || [])[0];
374
+ }));
375
+ });
376
+ }
339
377
  }
340
378
  exports.MySQLStorage = MySQLStorage;
@@ -1,6 +1,6 @@
1
1
  import { Client } from 'pg';
2
2
  import { Storage } from '.';
3
- import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings } from '../models';
3
+ import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncedFiles, IntegrationSyncSettings } from '../models';
4
4
  export interface PostgreStorageConfig {
5
5
  host?: string;
6
6
  connectionString?: string;
@@ -21,6 +21,7 @@ export declare class PostgreStorage implements Storage {
21
21
  constructor(config: PostgreStorageConfig);
22
22
  executeQuery<T>(command: (client: Client) => Promise<T>): Promise<T>;
23
23
  migrate(): Promise<void>;
24
+ addColumns(client: Client): Promise<void>;
24
25
  addTables(client: Client): Promise<void>;
25
26
  saveCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
26
27
  updateCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
@@ -46,4 +47,7 @@ export declare class PostgreStorage implements Storage {
46
47
  saveFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
47
48
  updateFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
48
49
  getFilesSnapshot(integrationId: string, crowdinId: string, provider: string): Promise<IntegrationFilesSnapshot | undefined>;
50
+ saveSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
51
+ updateSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
52
+ getSyncedFiles(integrationId: string, crowdinId: string): Promise<IntegrationSyncedFiles | undefined>;
49
53
  }
@@ -48,6 +48,8 @@ class PostgreStorage {
48
48
  try {
49
49
  yield this.executeQuery(this.addTables);
50
50
  this._res && this._res();
51
+ // TODO: temporary code
52
+ yield this.executeQuery(this.addColumns);
51
53
  }
52
54
  catch (e) {
53
55
  console.error(e);
@@ -55,6 +57,22 @@ class PostgreStorage {
55
57
  }
56
58
  });
57
59
  }
60
+ addColumns(client) {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ const tableName = 'app_metadata';
63
+ const newColumns = ['crowdin_id'];
64
+ const tableInfo = yield client.query('SELECT column_name FROM information_schema.columns WHERE table_name = $1', [tableName]);
65
+ tableInfo.rows.map((columnInfo) => __awaiter(this, void 0, void 0, function* () {
66
+ const index = newColumns.indexOf(columnInfo.column_name);
67
+ if (~index) {
68
+ newColumns.splice(index, 1);
69
+ }
70
+ }));
71
+ for (const column of newColumns) {
72
+ yield client.query(`ALTER TABLE ${tableName} ADD COLUMN ${column} varchar NULL;`);
73
+ }
74
+ });
75
+ }
58
76
  addTables(client) {
59
77
  return __awaiter(this, void 0, void 0, function* () {
60
78
  yield client.query(`
@@ -97,7 +115,7 @@ class PostgreStorage {
97
115
  (
98
116
  id varchar primary key,
99
117
  data varchar,
100
- crowdin_id varchar,
118
+ crowdin_id varchar
101
119
  )
102
120
  `);
103
121
  yield client.query(`
@@ -110,6 +128,15 @@ class PostgreStorage {
110
128
  provider varchar not null
111
129
  )
112
130
  `);
131
+ yield client.query(`
132
+ create table if not exists synced_files
133
+ (
134
+ id serial primary key,
135
+ integration_id varchar not null,
136
+ crowdin_id varchar not null,
137
+ file_ids varchar
138
+ )
139
+ `);
113
140
  });
114
141
  }
115
142
  saveCrowdinCredentials(credentials) {
@@ -332,5 +359,34 @@ class PostgreStorage {
332
359
  }));
333
360
  });
334
361
  }
362
+ saveSyncedFiles(fileIds, integrationId, crowdinId) {
363
+ return __awaiter(this, void 0, void 0, function* () {
364
+ yield this.dbPromise;
365
+ yield this.executeQuery((client) => client.query('INSERT INTO synced_files(file_ids, integration_id, crowdin_id) VALUES ($1, $2, $3)', [
366
+ fileIds,
367
+ integrationId,
368
+ crowdinId,
369
+ ]));
370
+ });
371
+ }
372
+ updateSyncedFiles(fileIds, integrationId, crowdinId) {
373
+ return __awaiter(this, void 0, void 0, function* () {
374
+ yield this.dbPromise;
375
+ yield this.executeQuery((client) => client.query('UPDATE synced_files SET file_ids = $1 WHERE integration_id = $2 AND crowdin_id = $3', [
376
+ fileIds,
377
+ integrationId,
378
+ crowdinId,
379
+ ]));
380
+ });
381
+ }
382
+ getSyncedFiles(integrationId, crowdinId) {
383
+ return __awaiter(this, void 0, void 0, function* () {
384
+ yield this.dbPromise;
385
+ return this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
386
+ const res = yield client.query('SELECT id, file_ids as "fileIds", integration_id as "integrationId", crowdin_id as "crowdinId" FROM synced_files WHERE integration_id = $1 AND crowdin_id = $2', [integrationId, crowdinId]);
387
+ return res === null || res === void 0 ? void 0 : res.rows[0];
388
+ }));
389
+ });
390
+ }
335
391
  }
336
392
  exports.PostgreStorage = PostgreStorage;
@@ -1,5 +1,5 @@
1
1
  import { Storage } from '.';
2
- import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings } from '../models';
2
+ import { CrowdinCredentials, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncedFiles, IntegrationSyncSettings } from '../models';
3
3
  export interface SQLiteStorageConfig {
4
4
  dbFolder: string;
5
5
  }
@@ -41,4 +41,7 @@ export declare class SQLiteStorage implements Storage {
41
41
  saveFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
42
42
  updateFilesSnapshot(files: any, integrationId: string, crowdinId: string, provider: string): Promise<void>;
43
43
  getFilesSnapshot(integrationId: string, crowdinId: string, provider: string): Promise<IntegrationFilesSnapshot | undefined>;
44
+ saveSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
45
+ updateSyncedFiles(fileIds: any, integrationId: string, crowdinId: string): Promise<void>;
46
+ getSyncedFiles(integrationId: string, crowdinId: string): Promise<IntegrationSyncedFiles | undefined>;
44
47
  }
@@ -185,6 +185,15 @@ class SQLiteStorage {
185
185
  files varchar null,
186
186
  provider varchar not null
187
187
  );
188
+ `, []);
189
+ yield this._run(`
190
+ create table if not exists synced_files
191
+ (
192
+ id integer not null primary key autoincrement,
193
+ integration_id varchar not null,
194
+ crowdin_id varchar not null,
195
+ file_ids varchar null
196
+ );
188
197
  `, []);
189
198
  this._res && this._res();
190
199
  // TODO: temporary code
@@ -351,5 +360,27 @@ class SQLiteStorage {
351
360
  }
352
361
  });
353
362
  }
363
+ saveSyncedFiles(fileIds, integrationId, crowdinId) {
364
+ return this.run('INSERT INTO synced_files(file_ids, integration_id, crowdin_id) VALUES (?, ?, ?)', [
365
+ fileIds,
366
+ integrationId,
367
+ crowdinId,
368
+ ]);
369
+ }
370
+ updateSyncedFiles(fileIds, integrationId, crowdinId) {
371
+ return this.run('UPDATE synced_files SET file_ids = ? WHERE integration_id = ? AND crowdin_id = ?', [
372
+ fileIds,
373
+ integrationId,
374
+ crowdinId,
375
+ ]);
376
+ }
377
+ getSyncedFiles(integrationId, crowdinId) {
378
+ return __awaiter(this, void 0, void 0, function* () {
379
+ const row = yield this.get('SELECT id, file_ids as fileIds, integration_id as integrationId, crowdin_id as crowdinId FROM synced_files WHERE integration_id = ? AND crowdin_id = ?', [integrationId, crowdinId]);
380
+ if (row) {
381
+ return row;
382
+ }
383
+ });
384
+ }
354
385
  }
355
386
  exports.SQLiteStorage = SQLiteStorage;
@@ -0,0 +1,2 @@
1
+ import { CreateOrUpdateSyncedFilesArgs } from '../models';
2
+ export declare function createOrUpdateSyncedFiles(args: CreateOrUpdateSyncedFilesArgs): Promise<void>;
@@ -0,0 +1,31 @@
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.createOrUpdateSyncedFiles = void 0;
13
+ const storage_1 = require("../storage");
14
+ const index_1 = require("./index");
15
+ function createOrUpdateSyncedFiles(args) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const { config, req } = args;
18
+ let fileIds = args.fileIds;
19
+ const existingFiles = yield (0, storage_1.getStorage)().getSyncedFiles(req.crowdinContext.clientId, req.crowdinContext.crowdinId);
20
+ if (existingFiles) {
21
+ fileIds = [...new Set([...JSON.parse(existingFiles.fileIds), ...fileIds])];
22
+ (0, index_1.log)(`Updating synced files ${JSON.stringify(fileIds, null, 2)}`, config.logger);
23
+ yield (0, storage_1.getStorage)().updateSyncedFiles(JSON.stringify(fileIds), req.crowdinContext.clientId, req.crowdinContext.crowdinId);
24
+ }
25
+ else {
26
+ (0, index_1.log)(`Saving synced files ${JSON.stringify(fileIds, null, 2)}`, config.logger);
27
+ yield (0, storage_1.getStorage)().saveSyncedFiles(JSON.stringify(fileIds), req.crowdinContext.clientId, req.crowdinContext.crowdinId);
28
+ }
29
+ });
30
+ }
31
+ exports.createOrUpdateSyncedFiles = createOrUpdateSyncedFiles;
@@ -0,0 +1,7 @@
1
+ import express from 'express';
2
+ declare module 'express-serve-static-core' {
3
+ interface Application {
4
+ baseListen: any;
5
+ }
6
+ }
7
+ export default express;
@@ -0,0 +1,21 @@
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
+ const express_1 = __importDefault(require("express"));
7
+ const terminus_1 = require("@godaddy/terminus");
8
+ express_1.default.application.baseListen = express_1.default.application.listen;
9
+ express_1.default.application.listen = function (...args) {
10
+ const [port, callback] = args;
11
+ const server = this.baseListen.call(this, port);
12
+ if (callback) {
13
+ callback();
14
+ }
15
+ (0, terminus_1.createTerminus)(server, {
16
+ timeout: Infinity,
17
+ useExit0: true,
18
+ });
19
+ return server;
20
+ };
21
+ exports.default = express_1.default;
@@ -6,21 +6,36 @@
6
6
  <div class="i_w">
7
7
  <div class="top">
8
8
  {{#if checkSubscription}}
9
- <crowdin-alert id="subscription-info" no-icon="true" type="warning" style="display: none;">
9
+ <crowdin-alert id="subscription-info" no-icon="true" type="warning" style="display: none; margin-bottom: 12px;">
10
10
  <div class="box-center">
11
11
  <p class="m-0"></p>
12
12
  <crowdin-button class="ml-1" primary onclick="window.open(subscriptionLink,'_blank')">Subscribe</crowdin-button>
13
13
  </div>
14
14
  </crowdin-alert>
15
15
  {{/if}}
16
- {{#if infoModal}}
17
- <crowdin-button icon-before="info" onclick="infoModal.open();">{{infoModal.title}}</crowdin-button>
18
- {{/if}}
19
- {{#if configurationFields}}
20
- <crowdin-button icon-before="settings" onclick="settingsModal.open();fillSettingsForm();">Settings</crowdin-button>
21
- {{/if}}
22
- <crowdin-button icon-before="account_circle" onclick="integrationLogout()">Log out</crowdin-button>
23
- {{#if uploadTranslations}}
16
+ <div class="top-button">
17
+ {{#if filtering}}
18
+ <div class="integration-filter">
19
+ <crowdin-integration-filter
20
+ {{#if filtering.syncStatus}}
21
+ enable-sync-status-filter
22
+ {{/if}}
23
+ integration-logo="logo.png"
24
+ ></crowdin-integration-filter>
25
+ </div>
26
+ {{/if}}
27
+
28
+ <div>
29
+ {{#if infoModal}}
30
+ <crowdin-button icon-before="info" onclick="infoModal.open();">{{infoModal.title}}</crowdin-button>
31
+ {{/if}}
32
+ {{#if configurationFields}}
33
+ <crowdin-button icon-before="settings" onclick="settingsModal.open();fillSettingsForm();">Settings</crowdin-button>
34
+ {{/if}}
35
+ <crowdin-button icon-before="account_circle" onclick="integrationLogout()">Log out</crowdin-button>
36
+ </div>
37
+ </div>
38
+ {{#if uploadTranslations}}
24
39
  <crowdin-alert id="translation-info" no-icon="true" style="display: none;">
25
40
  <div class="box-center">
26
41
  <p class="info-text">
@@ -31,7 +46,7 @@
31
46
  </div>
32
47
  <crowdin-button onclick="closeAlert(this)" class="dismiss-alert" icon>close</crowdin-button>
33
48
  </crowdin-alert>
34
- {{/if}}
49
+ {{/if}}
35
50
  </div>
36
51
  <crowdin-simple-integration
37
52
  {{#if syncNewElements.crowdin}}
@@ -248,6 +263,11 @@
248
263
  const appComponent = document.querySelector('crowdin-simple-integration');
249
264
  const subscriptionModal = document.getElementById('subscription-modal');
250
265
 
266
+ {{#if filtering}}
267
+ let syncedFiles = [];
268
+ const filterIntegration = document.querySelector('crowdin-integration-filter');
269
+ {{/if}}
270
+
251
271
  const folderType = '0';
252
272
  const fileType = '1';
253
273
  const branchType = '2';
@@ -297,10 +317,16 @@
297
317
  .then((res) => {
298
318
  project = res;
299
319
  appComponent.setCrowdinLanguagesData(project.targetLanguages)
320
+ {{#if filtering}}
321
+ filterIntegration.setLanguages(project.targetLanguages)
322
+ {{/if}}
300
323
  })
301
324
  {{#or withCronSync webhooks}}
302
325
  .then(() => getSyncSettings('crowdin'))
303
326
  {{/or}}
327
+ {{#if filtering}}
328
+ .then(() => getSyncedFiles())
329
+ {{/if}}
304
330
  .catch(e => catchRejection(e, 'Can\'t fetch Crowdin data'))
305
331
  .finally(() => (appComponent.setAttribute('is-crowdin-loading', false)));
306
332
  }
@@ -761,6 +787,34 @@
761
787
  }
762
788
  checkAlert(translationInfo);
763
789
  {{/if}}
790
+
791
+ {{#if filtering}}
792
+ document.body.addEventListener("integrationFilterChange", filterFiles);
793
+
794
+ function filterFiles(event) {
795
+ const filter = event.detail;
796
+
797
+ if (filter.languages) {
798
+ const languageIds = filter.languages === 'all' ? [] : [filter.languages];
799
+ appComponent.filterCrowdinFilesByLanguages(languageIds);
800
+ }
801
+ if (filter.sync) {
802
+ const fileId = filter.sync === 'all' ? [] : syncedFiles;
803
+ appComponent.filterIntegrationFilesByIds(fileId, filter.sync !== 'not_synced');
804
+ }
805
+ }
806
+
807
+ function getSyncedFiles() {
808
+ checkOrigin()
809
+ .then(restParams => fetch('/api/synced-files' + restParams))
810
+ .then(checkResponse)
811
+ .then((res) => {
812
+ syncedFiles = res;
813
+ })
814
+ .catch(e => catchRejection(e, 'Can\'t fetch file progress'));
815
+ }
816
+
817
+ {{/if}}
764
818
  </script>
765
819
 
766
820
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.29.4",
3
+ "version": "0.30.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",
@@ -15,11 +15,12 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@crowdin/crowdin-apps-functions": "0.5.1",
18
+ "@godaddy/terminus": "^4.12.1",
18
19
  "@types/pg": "^8.6.6",
19
20
  "amqplib": "^0.10.3",
20
21
  "crypto-js": "^4.0.0",
21
22
  "express": "4.18.2",
22
- "express-handlebars": "^5.3.4",
23
+ "express-handlebars": "^5.3.5",
23
24
  "mysql2": "^2.3.3",
24
25
  "node-cron": "^3.0.2",
25
26
  "pg": "^8.10.0",
@@ -30,7 +31,7 @@
30
31
  },
31
32
  "devDependencies": {
32
33
  "@babel/preset-react": "^7.22.3",
33
- "@emotion/react": "^11.10.6",
34
+ "@emotion/react": "^11.11.1",
34
35
  "@emotion/styled": "^11.10.6",
35
36
  "@mui/icons-material": "^5.11.16",
36
37
  "@mui/material": "^5.11.12",
@@ -45,7 +46,7 @@
45
46
  "@rollup/plugin-replace": "^5.0.2",
46
47
  "@rollup/plugin-terser": "^0.4.0",
47
48
  "@types/amqplib": "^0.10.1",
48
- "@types/crypto-js": "^4.0.0",
49
+ "@types/crypto-js": "^4.1.1",
49
50
  "@types/express": "4.17.17",
50
51
  "@types/express-handlebars": "^5.3.1",
51
52
  "@types/jest": "^29.5.2",
@@ -63,7 +64,7 @@
63
64
  "react": "^18.2.0",
64
65
  "react-dom": "^18.2.0",
65
66
  "rollup": "^3.20.2",
66
- "ts-jest": "^29.1.0",
67
+ "ts-jest": "^29.1.1",
67
68
  "typescript": "^4.9.5"
68
69
  },
69
70
  "repository": {