@kumori/aurora-backend-handler 1.0.50 → 1.0.52

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.
@@ -222,6 +222,7 @@ export const createAccount = async (account: Account, security: Security) => {
222
222
  username: account.cloudProvider.username || "",
223
223
  password: account.cloudProvider.password || "",
224
224
  region: account.cloudProvider?.region || "",
225
+ project_id: account.cloudProvider?.project_id || "",
225
226
  }
226
227
  : {
227
228
  method: providerName,
@@ -333,6 +334,7 @@ export const createAccount = async (account: Account, security: Security) => {
333
334
  password: account.cloudProvider.password || "",
334
335
  region: account.cloudProvider?.region || "",
335
336
  domain: account.cloudProvider?.domain || "",
337
+ project_id: account.cloudProvider?.project_id || "",
336
338
  }
337
339
  : {
338
340
  method: providerName,
@@ -611,6 +613,7 @@ export const deleteAccount = async (account: Account, security: Security) => {
611
613
  credentials: {
612
614
  username: account.cloudProvider.username,
613
615
  password: account.cloudProvider.password,
616
+ project_id: account.cloudProvider.project_id || "",
614
617
  },
615
618
  },
616
619
  };
@@ -625,6 +628,7 @@ export const deleteAccount = async (account: Account, security: Security) => {
625
628
  username: account.cloudProvider.username,
626
629
  password: account.cloudProvider.password,
627
630
  domain: account.cloudProvider.domain,
631
+ project_id: account.cloudProvider.project_id || "",
628
632
  },
629
633
  },
630
634
  };
@@ -990,6 +994,7 @@ export const updateAccount = async (account: Account, security: Security) => {
990
994
  username: account.cloudProvider.username || "",
991
995
  password: account.cloudProvider.password || "",
992
996
  region: account.cloudProvider?.region || "",
997
+ project_id: account.cloudProvider?.project_id || "",
993
998
  }
994
999
  : {
995
1000
  method: providerName,
@@ -1099,6 +1104,7 @@ export const updateAccount = async (account: Account, security: Security) => {
1099
1104
  password: account.cloudProvider.password || "",
1100
1105
  region: account.cloudProvider?.region || "",
1101
1106
  domain: account.cloudProvider?.domain || "",
1107
+ project_id: account.cloudProvider?.project_id || "",
1102
1108
  }
1103
1109
  : {
1104
1110
  method: providerName,
@@ -7,6 +7,7 @@ import {
7
7
  makeGlobalWebSocketRequest,
8
8
  } from "../websocket-manager";
9
9
  import { Link, Notification, Service } from "@kumori/aurora-interfaces";
10
+ import { Revision } from "@kumori/aurora-interfaces/interfaces/revision-interface";
10
11
  let pendingLinks = new Map<string, Link[]>();
11
12
  /**
12
13
  * Function to deploy a service
@@ -15,13 +16,13 @@ let pendingLinks = new Map<string, Link[]>();
15
16
  export const deployService = async (data: Service, token: string) => {
16
17
  try {
17
18
  const url = new URL(
18
- `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${data.tenant}/service/${data.name}`,
19
+ `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${data.tenant}/service/${data.name}`
19
20
  );
20
21
  url.searchParams.append("dryrun", "false");
21
22
  url.searchParams.append("accept", "true");
22
23
  url.searchParams.append("wait", "30000");
23
24
  url.searchParams.append("validate", "true");
24
- if (data.dsl) {
25
+ if(data.dsl){
25
26
  url.searchParams.append("dsl", "true");
26
27
  }
27
28
  if (data.serviceData) {
@@ -32,7 +33,7 @@ export const deployService = async (data: Service, token: string) => {
32
33
  JSON.stringify({
33
34
  targetAccount: data.account,
34
35
  targetEnvironment: data.environment,
35
- }),
36
+ })
36
37
  );
37
38
  formData.append("labels", JSON.stringify({ project: data.project }));
38
39
  formData.append("comment", " ");
@@ -47,7 +48,7 @@ export const deployService = async (data: Service, token: string) => {
47
48
  const jsonResponse = await response.json();
48
49
 
49
50
  const isTimeout = jsonResponse?.events?.some(
50
- (event: any) => event.content === "_timeout_",
51
+ (event: any) => event.content === "_timeout_"
51
52
  );
52
53
 
53
54
  if (isTimeout) {
@@ -80,7 +81,7 @@ export const deployService = async (data: Service, token: string) => {
80
81
  const jsonResponse = await response.json();
81
82
 
82
83
  const isTimeout = jsonResponse?.events?.some(
83
- (event: any) => event.content === "_timeout_",
84
+ (event: any) => event.content === "_timeout_"
84
85
  );
85
86
 
86
87
  if (isTimeout) {
@@ -110,7 +111,7 @@ export const redeployService = async (data: Service) => {
110
111
  try {
111
112
  const formData = await deployServiceHelper(data);
112
113
  const url = new URL(
113
- `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${data.tenant}/service/${data.name}/revision/${data.currentRevision}`,
114
+ `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${data.tenant}/service/${data.name}/revision/${data.currentRevision}`
114
115
  );
115
116
  url.searchParams.append("dryrun", "false");
116
117
  url.searchParams.append("accept", "true");
@@ -129,7 +130,7 @@ export const redeployService = async (data: Service) => {
129
130
  const jsonResponse = await response.json();
130
131
 
131
132
  const isTimeout = jsonResponse?.events?.some(
132
- (event: any) => event.content === "_timeout_",
133
+ (event: any) => event.content === "_timeout_"
133
134
  );
134
135
 
135
136
  if (isTimeout) {
@@ -162,7 +163,7 @@ export const deleteService = async (data: Service, security: string) => {
162
163
  deleteBody,
163
164
  30000,
164
165
  "DELETE",
165
- data.name,
166
+ data.name
166
167
  );
167
168
  return response;
168
169
  } catch (err) {
@@ -187,7 +188,7 @@ export const restartService = async (data: Service, security: string) => {
187
188
  restartBody,
188
189
  30000,
189
190
  "RESTART",
190
- data.name,
191
+ data.name
191
192
  );
192
193
 
193
194
  const updatedService: Service = {
@@ -208,63 +209,31 @@ export const restartService = async (data: Service, security: string) => {
208
209
  }
209
210
  };
210
211
  const generateLinkBody = (data: Service, link: Link) => {
211
- console.log("[Backend Handler] generateLinkBody - Link:", link);
212
- console.log("[Backend Handler] generateLinkBody - Service:", data);
213
-
214
212
  const originInClient = data.clientChannels.find(
215
213
  (channel) =>
216
- channel.name === link.originChannel ||
217
- channel.from === link.originChannel,
214
+ channel.name === link.originChannel || channel.from === link.originChannel
218
215
  );
219
216
  const originInServer = data.serverChannels.find(
220
217
  (channel) =>
221
- channel.name === link.originChannel ||
222
- channel.from === link.originChannel,
218
+ channel.name === link.originChannel || channel.from === link.originChannel
223
219
  );
224
220
  const originInDuplex = data.duplexChannels.find(
225
221
  (channel) =>
226
- channel.name === link.originChannel ||
227
- channel.from === link.originChannel,
222
+ channel.name === link.originChannel || channel.from === link.originChannel
228
223
  );
229
224
  const targetInClient = data.clientChannels.find(
230
225
  (channel) =>
231
- channel.name === link.targetChannel ||
232
- channel.from === link.targetChannel,
226
+ channel.name === link.targetChannel || channel.from === link.targetChannel
233
227
  );
234
228
  const targetInServer = data.serverChannels.find(
235
229
  (channel) =>
236
- channel.name === link.targetChannel ||
237
- channel.from === link.targetChannel,
230
+ channel.name === link.targetChannel || channel.from === link.targetChannel
238
231
  );
239
232
  const targetInDuplex = data.duplexChannels.find(
240
233
  (channel) =>
241
- channel.name === link.targetChannel ||
242
- channel.from === link.targetChannel,
243
- );
244
- console.log(
245
- "[Backend Handler] generateLinkBody - Origin in client:",
246
- originInClient,
247
- );
248
- console.log(
249
- "[Backend Handler] generateLinkBody - Origin in server:",
250
- originInServer,
251
- );
252
- console.log(
253
- "[Backend Handler] generateLinkBody - Origin in duplex:",
254
- originInDuplex,
255
- );
256
- console.log(
257
- "[Backend Handler] generateLinkBody - Target in client:",
258
- targetInClient,
259
- );
260
- console.log(
261
- "[Backend Handler] generateLinkBody - Target in server:",
262
- targetInServer,
263
- );
264
- console.log(
265
- "[Backend Handler] generateLinkBody - Target in duplex:",
266
- targetInDuplex,
234
+ channel.name === link.targetChannel || channel.from === link.targetChannel
267
235
  );
236
+
268
237
  let linkBody;
269
238
  if (originInClient) {
270
239
  linkBody = {
@@ -322,7 +291,7 @@ const generateLinkBody = (data: Service, link: Link) => {
322
291
  };
323
292
  } else {
324
293
  console.warn(
325
- `No se encontraron canales para el enlace: origin=${link.origin}, target=${link.target}`,
294
+ `No se encontraron canales para el enlace: origin=${link.origin}, target=${link.target}`
326
295
  );
327
296
  linkBody = {
328
297
  client_tenant: data.tenant,
@@ -333,8 +302,6 @@ const generateLinkBody = (data: Service, link: Link) => {
333
302
  server_channel: link.targetChannel,
334
303
  };
335
304
  }
336
-
337
- console.log("[Backend Handler] generateLinkBody - Link body:", linkBody);
338
305
  return linkBody;
339
306
  };
340
307
  export const linkPendingServices = async (service: Service, token: string) => {
@@ -352,7 +319,7 @@ export const linkPendingServices = async (service: Service, token: string) => {
352
319
  linkBody,
353
320
  30000,
354
321
  "LINK",
355
- service.name,
322
+ service.name
356
323
  );
357
324
 
358
325
  const notification: Notification = {
@@ -386,7 +353,7 @@ export const linkPendingServices = async (service: Service, token: string) => {
386
353
  };
387
354
  eventHelper.notification.publish.creation(notification);
388
355
  }
389
- }),
356
+ })
390
357
  );
391
358
  }
392
359
  };
@@ -408,7 +375,7 @@ export const requestRevisionData = async (service: Service, token: string) => {
408
375
  "GET_REVISION",
409
376
  service.name,
410
377
  "service",
411
- service,
378
+ service
412
379
  );
413
380
  return response;
414
381
  } catch (err) {
@@ -435,163 +402,203 @@ export const updateService = async (
435
402
  // pendingLinks.set(data.name, newLinksToCreate);
436
403
  // await linkPendingServices(serviceWithNewLinks, token);
437
404
  // }
438
-
439
- const parameterObject: Record<string, any> = {};
440
- if (data.parameters && data.parameters.length > 0) {
441
- data.parameters.forEach((param) => {
442
- const key = param.configKey || param.name;
443
- const paramType = param.type?.toLowerCase();
444
- if (paramType === "number" || paramType === "integer") {
445
- parameterObject[key] = Number(param.value) || 0;
446
- } else if (paramType === "boolean") {
447
- parameterObject[key] = param.value === "true";
448
- } else {
449
- parameterObject[key] = param.value;
450
- }
451
- });
405
+ const url = new URL(
406
+ `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${data.tenant}/service/${data.name}/revision/${data.currentRevision}`,
407
+ );
408
+ if (data.dsl) {
409
+ url.searchParams.append("dsl", "true");
452
410
  }
453
-
454
- const resourceObject: Record<string, any> = {};
455
- if (data.resources && data.resources.length > 0) {
456
- data.resources.forEach((resource) => {
457
- if (resource.type === "volume") {
458
- resourceObject[resource.name] = {
459
- volume: {
460
- kind: "storage",
461
- size: parseInt(resource.value) || 1,
462
- unit: "G",
463
- type: resource.kind,
464
- },
465
- };
466
- } else if (resource.type === "secret") {
467
- resourceObject[resource.name] = {
468
- secret: `${data.tenant}/${resource.value}`,
469
- };
470
- } else if (resource.type === "domain") {
471
- resourceObject[resource.name] = {
472
- domain: `${data.tenant}/${resource.value}`,
473
- };
474
- } else if (resource.type === "ca") {
475
- resourceObject[resource.name] = {
476
- ca: `${data.tenant}/${resource.value}`,
477
- };
478
- } else if (resource.type === "certificate") {
479
- resourceObject[resource.name] = {
480
- certificate: `${data.tenant}/${resource.value}`,
481
- };
482
- } else if (resource.type === "port") {
483
- resourceObject[resource.name] = {
484
- port: `${data.tenant}/${resource.value}`,
485
- };
486
- }
411
+ if (data.serviceData) {
412
+ const formData = new FormData();
413
+ formData.append("type", "update-bundle");
414
+ formData.append("bundle", data.serviceData);
415
+ formData.append(
416
+ "meta",
417
+ JSON.stringify({
418
+ targetAccount: data.account,
419
+ targetEnvironment: data.environment,
420
+ }),
421
+ );
422
+ formData.append("labels", JSON.stringify({ project: data.project }));
423
+ formData.append("comment", " ");
424
+ const response = await fetch(url.toString(), {
425
+ method: "POST",
426
+ body: formData,
487
427
  });
488
- }
489
-
490
- let previousRevision = 1;
491
- if (data.currentRevision) {
492
- previousRevision = parseInt(data.currentRevision.toString(), 10);
493
- if (isNaN(previousRevision)) {
494
- console.warn("currentRevision is not a valid number, using 1");
495
- previousRevision = 1;
428
+ if (!response.ok) {
429
+ throw new Error(`HTTP error! status: ${response.status}`);
496
430
  }
497
- } else {
498
- previousRevision = getLatestRevision(data.revisions) || 1;
499
- }
500
431
 
501
- const scaleConfig: any = {};
502
- if (data.role && data.role.length > 0) {
503
- scaleConfig.detail = {};
504
- data.role.forEach((role) => {
505
- scaleConfig.detail[role.name] = {
506
- hsize: role.hsize || scale || data.minReplicas || 1,
507
- };
508
- });
432
+ const jsonResponse = await response.json();
433
+ const isTimeout = jsonResponse?.events?.some(
434
+ (event: any) => event.content === "_timeout_",
435
+ );
436
+
437
+ if (isTimeout) {
438
+ console.error("Timeout en la petición:", {
439
+ isOk: false,
440
+ code: "TIMEOUT",
441
+ error: "_timeout_",
442
+ });
443
+ }
509
444
  } else {
510
- scaleConfig.hsize = scale || data.minReplicas || 1;
511
- }
512
- const meta = {
513
- scaling: {
514
- simple:
515
- data.role?.reduce(
516
- (acc, role) => {
517
- if (role.scalling && role.name) {
518
- acc[role.name] = {
519
- scale_up: {
520
- cpu: Math.min(parseInt(role.scalling.cpu.up) || 0, 100),
521
- memory: Math.min(
522
- parseInt(role.scalling.memory.up) || 0,
523
- 100,
524
- ),
525
- },
526
- scale_down: {
527
- cpu: Math.min(parseInt(role.scalling.cpu.down) || 0, 100),
528
- memory: Math.min(
529
- parseInt(role.scalling.memory.down) || 0,
530
- 100,
531
- ),
532
- },
533
- hysteresis: parseInt(role.scalling.histeresys) || 0,
534
- min_replicas: role.scalling.instances.min || 0,
535
- max_replicas: role.scalling.instances.max || 0,
536
- };
537
- }
538
- return acc;
539
- },
540
- {} as Record<string, any>,
541
- ) || {},
542
- },
543
- };
445
+ const parameterObject: Record<string, any> = {};
446
+ if (data.parameters && data.parameters.length > 0) {
447
+ data.parameters.forEach((param) => {
448
+ const key = param.configKey || param.name;
449
+ const paramType = param.type?.toLowerCase();
450
+ if (paramType === "number" || paramType === "integer") {
451
+ parameterObject[key] = Number(param.value) || 0;
452
+ } else if (paramType === "boolean") {
453
+ parameterObject[key] = param.value === "true";
454
+ } else {
455
+ parameterObject[key] = param.value;
456
+ }
457
+ });
458
+ }
544
459
 
545
- const updateBody = {
546
- spec: {
547
- type: "update-config",
548
- comment: "Service configuration update",
549
- config: {
550
- parameter: parameterObject,
551
- resource: resourceObject,
552
- resilience: 0,
553
- scale: scaleConfig,
554
- },
555
- meta: meta,
556
- },
557
- tenant: data.tenant,
558
- service: data.name,
559
- previous: previousRevision,
560
- };
460
+ const resourceObject: Record<string, any> = {};
461
+ if (data.resources && data.resources.length > 0) {
462
+ data.resources.forEach((resource) => {
463
+ if (resource.type === "volume") {
464
+ resourceObject[resource.name] = {
465
+ volume: {
466
+ kind: "storage",
467
+ size: parseInt(resource.value) || 1,
468
+ unit: "G",
469
+ type: resource.kind,
470
+ },
471
+ };
472
+ } else if (resource.type === "secret") {
473
+ resourceObject[resource.name] = {
474
+ secret: `${data.tenant}/${resource.value}`,
475
+ };
476
+ } else if (resource.type === "domain") {
477
+ resourceObject[resource.name] = {
478
+ domain: `${data.tenant}/${resource.value}`,
479
+ };
480
+ } else if (resource.type === "ca") {
481
+ resourceObject[resource.name] = {
482
+ ca: `${data.tenant}/${resource.value}`,
483
+ };
484
+ } else if (resource.type === "certificate") {
485
+ resourceObject[resource.name] = {
486
+ certificate: `${data.tenant}/${resource.value}`,
487
+ };
488
+ } else if (resource.type === "port") {
489
+ resourceObject[resource.name] = {
490
+ port: `${data.tenant}/${resource.value}`,
491
+ };
492
+ }
493
+ });
494
+ }
561
495
 
562
- const response = await makeGlobalWebSocketRequest(
563
- "revision:update_revision",
564
- updateBody,
565
- 30000,
566
- "UPDATE_CONFIG",
567
- data.name,
568
- );
496
+ let previousRevision = 1;
497
+ if (data.currentRevision) {
498
+ previousRevision = parseInt(data.currentRevision.toString(), 10);
499
+ if (isNaN(previousRevision)) {
500
+ console.warn("currentRevision is not a valid number, using 1");
501
+ previousRevision = 1;
502
+ }
503
+ } else {
504
+ previousRevision = getLatestRevision(data.revisions) || 1;
505
+ }
569
506
 
570
- const updatedService: Service = {
571
- ...data,
572
- status: {
573
- code: "PENDING",
574
- message: "",
575
- timestamp: "",
576
- args: [],
577
- },
578
- };
579
- eventHelper.service.publish.updated(updatedService);
507
+ const scaleConfig: any = {};
508
+ if (data.role && data.role.length > 0) {
509
+ scaleConfig.detail = {};
510
+ data.role.forEach((role) => {
511
+ scaleConfig.detail[role.name] = {
512
+ hsize: role.hsize || scale || data.minReplicas || 1,
513
+ };
514
+ });
515
+ } else {
516
+ scaleConfig.hsize = scale || data.minReplicas || 1;
517
+ }
518
+ const meta = {
519
+ scaling: {
520
+ simple:
521
+ data.role?.reduce(
522
+ (acc, role) => {
523
+ if (role.scalling && role.name) {
524
+ acc[role.name] = {
525
+ scale_up: {
526
+ cpu: Math.min(parseInt(role.scalling.cpu.up) || 0, 100),
527
+ memory: Math.min(
528
+ parseInt(role.scalling.memory.up) || 0,
529
+ 100,
530
+ ),
531
+ },
532
+ scale_down: {
533
+ cpu: Math.min(parseInt(role.scalling.cpu.down) || 0, 100),
534
+ memory: Math.min(
535
+ parseInt(role.scalling.memory.down) || 0,
536
+ 100,
537
+ ),
538
+ },
539
+ hysteresis: parseInt(role.scalling.histeresys) || 0,
540
+ min_replicas: role.scalling.instances.min || 0,
541
+ max_replicas: role.scalling.instances.max || 0,
542
+ };
543
+ }
544
+ return acc;
545
+ },
546
+ {} as Record<string, any>,
547
+ ) || {},
548
+ },
549
+ };
580
550
 
581
- const updateNotification: Notification = {
582
- type: "success",
583
- subtype: "service-updated",
584
- date: Date.now().toString(),
585
- status: "unread",
586
- callToAction: false,
587
- data: {
588
- service: data.name,
551
+ const updateBody = {
552
+ spec: {
553
+ type: "update-config",
554
+ comment: "Service configuration update",
555
+ config: {
556
+ parameter: parameterObject,
557
+ resource: resourceObject,
558
+ resilience: 0,
559
+ scale: scaleConfig,
560
+ },
561
+ meta: meta,
562
+ },
589
563
  tenant: data.tenant,
590
- },
591
- };
564
+ service: data.name,
565
+ previous: previousRevision,
566
+ };
567
+
568
+ const response = await makeGlobalWebSocketRequest(
569
+ "revision:update_revision",
570
+ updateBody,
571
+ 30000,
572
+ "UPDATE_CONFIG",
573
+ data.name,
574
+ );
575
+ const updatedService: Service = {
576
+ ...data,
577
+ status: {
578
+ code: "PENDING",
579
+ message: "",
580
+ timestamp: "",
581
+ args: [],
582
+ },
583
+ };
584
+ eventHelper.service.publish.updated(updatedService);
585
+
586
+ const updateNotification: Notification = {
587
+ type: "success",
588
+ subtype: "service-updated",
589
+ date: Date.now().toString(),
590
+ status: "unread",
591
+ callToAction: false,
592
+ data: {
593
+ service: data.name,
594
+ tenant: data.tenant,
595
+ },
596
+ };
597
+
598
+ eventHelper.notification.publish.creation(updateNotification);
599
+ return response;
600
+ }
592
601
 
593
- eventHelper.notification.publish.creation(updateNotification);
594
- return response;
595
602
  } catch (err) {
596
603
  console.error("Error updating service configuration via WebSocket:", err);
597
604
  const notification: Notification = {
@@ -616,7 +623,7 @@ export const updateService = async (
616
623
  };
617
624
  export const unlinkServices = async (service: Service, token: string) => {
618
625
  const deleteLinks: Link[] = service.links.filter(
619
- (link) => link.delete === true,
626
+ (link) => link.delete === true
620
627
  );
621
628
  if (deleteLinks.length > 0) {
622
629
  await Promise.all(
@@ -631,7 +638,7 @@ export const unlinkServices = async (service: Service, token: string) => {
631
638
  unlinkBody,
632
639
  30000,
633
640
  "UNLINK",
634
- service.name,
641
+ service.name
635
642
  );
636
643
 
637
644
  const unlinkNotification: Notification = {
@@ -667,7 +674,7 @@ export const unlinkServices = async (service: Service, token: string) => {
667
674
  };
668
675
  eventHelper.notification.publish.creation(notification);
669
676
  }
670
- }),
677
+ })
671
678
  );
672
679
  }
673
680
  };
@@ -692,7 +699,7 @@ export const updateServiceLinks = async (link: Link, token: string) => {
692
699
  linkBody,
693
700
  30000,
694
701
  "UNLINK",
695
- link.origin,
702
+ link.origin
696
703
  );
697
704
 
698
705
  // const unlinkNotification: Notification = {
@@ -738,7 +745,7 @@ export const updateServiceLinks = async (link: Link, token: string) => {
738
745
  linkBody,
739
746
  30000,
740
747
  "LINK",
741
- link.origin,
748
+ link.origin
742
749
  );
743
750
 
744
751
  const notification: Notification = {
@@ -794,7 +801,7 @@ export const changeRevision = async (data: Service, token: string) => {
794
801
  revisionBody,
795
802
  30000,
796
803
  "UPDATE_REVISION",
797
- data.name,
804
+ data.name
798
805
  );
799
806
  const notification: Notification = {
800
807
  type: "success",
@@ -826,10 +833,10 @@ export const changeRevision = async (data: Service, token: string) => {
826
833
  eventHelper.notification.publish.creation(notification);
827
834
  }
828
835
  };
829
- function getLatestRevision(revisions: string[]): number | null {
836
+ function getLatestRevision(revisions: Revision[]): number | null {
830
837
  if (!revisions || revisions.length === 0) {
831
838
  return null;
832
839
  }
833
-
834
- return Math.max(...revisions.map(Number));
835
- }
840
+
841
+ return Math.max(...revisions.map((revision) => Number(revision.id)));
842
+ }