@kumori/aurora-backend-handler 1.0.99 → 1.0.111

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/event-helper.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { loadUser } from './api/user-api-service';
1
2
  import { Account, Environment, Link, MarketplaceItem, MarketplaceService, Organization, PlanProvider, Registry, Tenant, tenantRole, User, Service, Notification, Resource } from "@kumori/aurora-interfaces";
2
3
  import { EventNames } from "./event-names";
3
4
  export interface RegistryUpdatePayload {
@@ -63,7 +64,7 @@ export class EventHelper {
63
64
  updateInvite: this.createEvent<{ tenant: string; user: string; role: tenantRole; }>(EventNames.UpdateInvite).publish,
64
65
  inviteUpdated: this.createEvent<{ tenant: string; user: string; role: tenantRole; }>(EventNames.InviteUpdated).publish,
65
66
  inviteUpdateError: this.createEvent<{ tenant: string; user: string; role: tenantRole; }>(EventNames.InviteUpdateError).publish,
66
- rejectInvite: this.createEvent<{ tenant: string; }>(EventNames.RejectInvite).publish,
67
+ rejectInvite: this.createEvent<{ tenant: string; leave: boolean }>(EventNames.RejectInvite).publish,
67
68
  inviteRejected: this.createEvent<{ user: string; tenant: string; }>(EventNames.InviteRejected).publish,
68
69
  inviteRejectError: this.createEvent<{ tenant: string; }>(EventNames.InviteRejectError).publish,
69
70
  createToken: this.createEvent<{ tenant: string; expiration: string; description: string }>(EventNames.CreateToken).publish,
@@ -104,7 +105,7 @@ export class EventHelper {
104
105
  updateInvite: this.createEvent<{ tenant: string; user: string; role: tenantRole; }>(EventNames.UpdateInvite).subscribe,
105
106
  inviteUpdated: this.createEvent<{ tenant: string; user: string; role: tenantRole; }>(EventNames.InviteUpdated).subscribe,
106
107
  inviteUpdateError: this.createEvent<{ tenant: string; user: string; role: tenantRole; }>(EventNames.InviteUpdateError).subscribe,
107
- rejectInvite: this.createEvent<{ tenant: string; }>(EventNames.RejectInvite).subscribe,
108
+ rejectInvite: this.createEvent<{ tenant: string; leave: boolean }>(EventNames.RejectInvite).subscribe,
108
109
  inviteRejected: this.createEvent<{ user: string; tenant: string; }>(EventNames.InviteRejected).subscribe,
109
110
  inviteRejectError: this.createEvent<{ tenant: string; }>(EventNames.InviteRejectError).subscribe,
110
111
  createToken: this.createEvent<{ tenant: string; expiration: string; description: string }>(EventNames.CreateToken).subscribe,
@@ -145,7 +146,7 @@ export class EventHelper {
145
146
  updateInvite: this.createEvent<{ tenant: string; user: string; role: tenantRole; }>(EventNames.UpdateInvite).unsubscribe,
146
147
  inviteUpdated: this.createEvent<{ tenant: string; user: string; role: tenantRole; }>(EventNames.InviteUpdated).unsubscribe,
147
148
  inviteUpdateError: this.createEvent<{ tenant: string; user: string; role: tenantRole; }>(EventNames.InviteUpdateError).unsubscribe,
148
- rejectInvite: this.createEvent<{ tenant: string; }>(EventNames.RejectInvite).unsubscribe,
149
+ rejectInvite: this.createEvent<{ tenant: string; leave: boolean }>(EventNames.RejectInvite).unsubscribe,
149
150
  inviteRejected: this.createEvent<{ user: string; tenant: string; }>(EventNames.InviteRejected).unsubscribe,
150
151
  inviteRejectError: this.createEvent<{ tenant: string; }>(EventNames.InviteRejectError).unsubscribe,
151
152
  createToken: this.createEvent<{ tenant: string; expiration: string; description: string }>(EventNames.CreateToken).unsubscribe,
@@ -405,6 +406,9 @@ export class EventHelper {
405
406
  deletionError: this.createEvent<Service>(EventNames.MarketplaceItemDeletionError).publish,
406
407
  loadItems: this.createEvent<string[]>(EventNames.LoadMarketplaceItems).publish,
407
408
  itemsLoaded: this.createEvent<MarketplaceItem[]>(EventNames.MarketplaceItemsLoaded).publish,
409
+ loadSchema: this.createEvent<string>(EventNames.LoadMarketplaceSchema).publish,
410
+ schemaLoaded: this.createEvent<MarketplaceItem>(EventNames.MarketplaceSchemaLoaded).publish,
411
+ schemaLoadError: this.createEvent<string>(EventNames.MarketplaceSchemaLoadError).publish,
408
412
  },
409
413
  subscribe: {
410
414
  deployItem: this.createEvent<MarketplaceService>(EventNames.DeployMarketplaceItem).subscribe,
@@ -418,6 +422,9 @@ export class EventHelper {
418
422
  deletionError: this.createEvent<Service>(EventNames.MarketplaceItemDeletionError).subscribe,
419
423
  loadItems: this.createEvent<string[]>(EventNames.LoadMarketplaceItems).subscribe,
420
424
  itemsLoaded: this.createEvent<MarketplaceItem[]>(EventNames.MarketplaceItemsLoaded).subscribe,
425
+ loadSchema: this.createEvent<string>(EventNames.LoadMarketplaceSchema).subscribe,
426
+ schemaLoaded: this.createEvent<MarketplaceItem>(EventNames.MarketplaceSchemaLoaded).subscribe,
427
+ schemaLoadError: this.createEvent<string>(EventNames.MarketplaceSchemaLoadError).subscribe,
421
428
  },
422
429
  unsubscribe: {
423
430
  deployItem: this.createEvent<MarketplaceService>(EventNames.DeployMarketplaceItem).unsubscribe,
@@ -431,6 +438,9 @@ export class EventHelper {
431
438
  deletionError: this.createEvent<Service>(EventNames.MarketplaceItemDeletionError).unsubscribe,
432
439
  loadItems: this.createEvent<string[]>(EventNames.LoadMarketplaceItems).unsubscribe,
433
440
  itemsLoaded: this.createEvent<MarketplaceItem[]>(EventNames.MarketplaceItemsLoaded).unsubscribe,
441
+ loadSchema: this.createEvent<string>(EventNames.LoadMarketplaceSchema).unsubscribe,
442
+ schemaLoaded: this.createEvent<MarketplaceItem>(EventNames.MarketplaceSchemaLoaded).unsubscribe,
443
+ schemaLoadError: this.createEvent<string>(EventNames.MarketplaceSchemaLoadError).unsubscribe,
434
444
  },
435
445
  };
436
446
  }
package/event-names.ts CHANGED
@@ -117,6 +117,9 @@ export enum EventNames {
117
117
  MarketplaceItemDeletionError = "marketplaceItemDeletionError",
118
118
  LoadMarketplaceItems = "loadMarketplaceItems",
119
119
  MarketplaceItemsLoaded = "marketplaceItemsLoaded",
120
+ LoadMarketplaceSchema = "loadMarketplaceSchema",
121
+ MarketplaceSchemaLoaded = "marketplaceSchemaLoaded",
122
+ MarketplaceSchemaLoadError = "marketplaceSchemaLoadError",
120
123
  // * Resource
121
124
  CreateResource = "createResource",
122
125
  ResourceCreated = "resourceCreated",
@@ -1,4 +1,4 @@
1
- import { Account, Notification } from "@kumori/aurora-interfaces";
1
+ import { Account, errors, Notification } from "@kumori/aurora-interfaces";
2
2
  const CREDENTIAL_ERROR_CODES = new Set([
3
3
  "_error_retrieving_credentials_",
4
4
  "_invalid_account_credentials_",
@@ -169,11 +169,14 @@ export const syncAccountStatusFromNotifications = (
169
169
  const accountName: string = notification.data?.account;
170
170
  if (!accountName) continue;
171
171
 
172
- const account = accountsMap.get(accountName);
172
+ const accountTenant: string = notification.data?.tenant ?? "";
173
+ const accountKey = accountTenant ? `${accountTenant}/${accountName}` : accountName;
174
+
175
+ const account = accountsMap.get(accountKey);
173
176
  if (!account || ACCOUNT_ERROR_STATUSES.has(account.status)) continue;
174
177
 
175
178
  const code: string = notification.info_content?.code ?? "";
176
- accountsMap.set(accountName, {
179
+ accountsMap.set(accountKey, {
177
180
  ...account,
178
181
  status: resolveErrorStatus(code),
179
182
  });
@@ -194,7 +197,8 @@ export const handleAccountEvent = ({
194
197
  extractCloudProviderCredentials(eventData);
195
198
  const accountLabels: Record<string, string> = eventData.meta.labels;
196
199
  const hasCredentials = "__axebow::managedCredentials" in accountLabels;
197
- const existingAccount = accountsMap.get(entityId);
200
+ const accountKey = accountTenantId ? `${accountTenantId}/${entityId}` : entityId;
201
+ const existingAccount = accountsMap.get(accountKey);
198
202
  const accountStatus = determineAccountStatus(eventData, existingAccount);
199
203
 
200
204
  const newAccount: Account = {
@@ -285,7 +289,7 @@ export const handleAccountOperationSuccess = ({
285
289
  shouldDelete: true,
286
290
  notification: {
287
291
  type: "success",
288
- subtype: "account-deleted",
292
+ subtype: errors.account.deleted.subtype,
289
293
  date: Date.now().toString(),
290
294
  status: "unread",
291
295
  callToAction: false,
@@ -304,7 +308,7 @@ export const handleAccountOperationSuccess = ({
304
308
  shouldDelete: false,
305
309
  notification: {
306
310
  type: "success",
307
- subtype: isCreate ? "account-created" : "account-updated",
311
+ subtype: isCreate ? errors.account.created.subtype : errors.account.updated.subtype,
308
312
  date: Date.now().toString(),
309
313
  status: "unread",
310
314
  callToAction: false,
@@ -345,12 +349,6 @@ export const handleAccountOperationError = ({
345
349
  const isCreate = action === "CREATE";
346
350
  const isUpdate = action === "UPDATE";
347
351
 
348
- const subtype = isCreate
349
- ? "account-creation-error"
350
- : isUpdate
351
- ? "account-update-error"
352
- : "account-deletion-error";
353
-
354
352
  const eventType: "creationError" | "updateError" | "deletionError" = isCreate
355
353
  ? "creationError"
356
354
  : isUpdate
@@ -359,9 +357,10 @@ export const handleAccountOperationError = ({
359
357
  const errorCode: string = error?.error?.code ?? error?.code ?? "";
360
358
  const errorStatus = resolveErrorStatus(errorCode);
361
359
 
360
+ const errEntry = isCreate ? errors.account.creationError : isUpdate ? errors.account.updateError : errors.account.deletionError;
362
361
  const notification: Notification = {
363
362
  type: "error",
364
- subtype,
363
+ subtype: errEntry.subtype,
365
364
  date: Date.now().toString(),
366
365
  status: "unread",
367
366
  info_content: {
@@ -1,4 +1,4 @@
1
- import { Account, Environment, Notification } from "@kumori/aurora-interfaces";
1
+ import { Account, Environment, errors, Notification } from "@kumori/aurora-interfaces";
2
2
 
3
3
 
4
4
 
@@ -56,7 +56,8 @@ export const handleEnvironmentEvent = ({
56
56
  }: HandleEnvironmentEventParams): HandleEnvironmentEventResult => {
57
57
  const tenantId = parentParts.tenant;
58
58
  const accountId = parentParts.account;
59
- const relatedAccount = accountsMap.get(accountId);
59
+ const accountKey = tenantId ? `${tenantId}/${accountId}` : accountId;
60
+ const relatedAccount = accountsMap.get(accountKey);
60
61
  let cloudProviderName = relatedAccount?.cloudProvider?.name || "";
61
62
 
62
63
  let pendingCloudProviderUpdate: { environmentId: string; accountId: string } | null = null;
@@ -68,7 +69,8 @@ export const handleEnvironmentEvent = ({
68
69
  };
69
70
  }
70
71
 
71
- const existingEnvironment = environmentsMap.get(entityId);
72
+ const envKey = tenantId && accountId ? `${tenantId}/${accountId}/${entityId}` : entityId;
73
+ const existingEnvironment = environmentsMap.get(envKey);
72
74
 
73
75
  const newEnvironment: Environment = {
74
76
  id: entityId,
@@ -78,17 +80,18 @@ export const handleEnvironmentEvent = ({
78
80
  logo: "",
79
81
  services: [],
80
82
  domains: [],
81
- status: eventData.meta?.deleted
82
- ? {
83
- code: "DELETING",
84
- message: `Environment ${entityId} is being deleted.`,
85
- timestamp: new Date().toISOString(),
86
- }
87
- : {
88
- code: eventData.status.state.code,
89
- message: eventData.status.state.message,
90
- timestamp: eventData.status.state.timestamp,
91
- },
83
+ status: (() => {
84
+ const existingCode = existingEnvironment?.status?.code;
85
+ const isPurging = existingCode === "PURGING" || existingCode === "CLEANING_ENVIRONMENT";
86
+ const eventCode = eventData.meta?.deleted ? "DELETING" : eventData.status?.state?.code;
87
+ if (isPurging && typeof eventCode === "string" && eventCode.startsWith("DELETING")) {
88
+ return { code: "PURGING", message: `Environment ${entityId} is being purged.`, timestamp: new Date().toISOString() };
89
+ }
90
+ if (eventData.meta?.deleted) {
91
+ return { code: "DELETING", message: `Environment ${entityId} is being deleted.`, timestamp: new Date().toISOString() };
92
+ }
93
+ return { code: eventData.status.state.code, message: eventData.status.state.message, timestamp: eventData.status.state.timestamp };
94
+ })(),
92
95
  highAvaliable: eventData.spec.highlyAvailable || false,
93
96
  usage: {
94
97
  current: {
@@ -181,7 +184,7 @@ export const handleEnvironmentOperationSuccess = ({
181
184
 
182
185
  const envNotification: Notification = {
183
186
  type: "success",
184
- subtype: "environment-cleaned",
187
+ subtype: errors.environment.purged.subtype,
185
188
  date: Date.now().toString(),
186
189
  status: "unread",
187
190
  callToAction: false,
@@ -240,23 +243,16 @@ export const handleEnvironmentOperationError = ({
240
243
  originalData,
241
244
  error,
242
245
  }: HandleEnvironmentOperationErrorParams): HandleEnvironmentOperationErrorResult => {
243
- let subtype: string;
244
- let eventType: "creationError" | "updateError" | "deletionError";
245
-
246
- if (action === "CREATE") {
247
- subtype = "environment-creation-error";
248
- eventType = "creationError";
249
- } else if (action === "UPDATE") {
250
- subtype = "environment-update-error";
251
- eventType = "updateError";
252
- } else {
253
- subtype = "environment-deletion-error";
254
- eventType = "deletionError";
255
- }
246
+ const eventType: "creationError" | "updateError" | "deletionError" = action === "CREATE"
247
+ ? "creationError"
248
+ : action === "UPDATE"
249
+ ? "updateError"
250
+ : "deletionError";
256
251
 
252
+ const envErrEntry = action === "CREATE" ? errors.environment.creationError : action === "UPDATE" ? errors.environment.updateError : errors.environment.deletionError;
257
253
  const envErrorNotification: Notification = {
258
254
  type: "error",
259
- subtype,
255
+ subtype: envErrEntry.subtype,
260
256
  date: Date.now().toString(),
261
257
  status: "unread",
262
258
  info_content: {
@@ -0,0 +1,109 @@
1
+ export const processMarketplaceSchemaResponse = (rawEntry: any, nameKey: string) => {
2
+ const roles: string[] = rawEntry.roles || [];
3
+ const roleName = roles.join(", ");
4
+ const schemas = rawEntry.schemas || [];
5
+
6
+ const processSchema = (schema: any) => {
7
+ const parameters: any[] = [];
8
+ const resources: any[] = [];
9
+ const channels: any[] = [];
10
+
11
+ const configProps = schema.properties?.config?.properties;
12
+ if (configProps) {
13
+ Object.entries(configProps).forEach(([key, value]: [string, any]) => {
14
+ parameters.push({
15
+ name: key,
16
+ type: value.type || "string",
17
+ required: schema.properties?.config?.required?.includes(key) || false,
18
+ defaultValue: value.default ?? value.enum?.[0] ?? value.const ?? undefined,
19
+ });
20
+ });
21
+ }
22
+
23
+ const volumeTypes = ["Registered", "NonReplicated", "Persisted", "Volatile", "Ephemeral", "Persistent"];
24
+ const isVolumeResource = (v: any): boolean => {
25
+ if (!v.oneOf) return false;
26
+ return v.oneOf.some((o: any) => {
27
+ if (o.oneOf) return o.oneOf.some((n: any) => volumeTypes.includes(n?.properties?.$kdsl?.const?.NamedType?.Name));
28
+ return volumeTypes.includes(o?.properties?.$kdsl?.const?.NamedType?.Name);
29
+ });
30
+ };
31
+
32
+ const resourceProps = schema.properties?.resource;
33
+ if (resourceProps?.properties) {
34
+ Object.entries(resourceProps.properties).forEach(([key, value]: [string, any]) => {
35
+ if (isVolumeResource(value)) {
36
+ resources.push({
37
+ name: key,
38
+ type: "volume",
39
+ required: resourceProps.required?.includes(key) || false,
40
+ });
41
+ } else {
42
+ const typeName = value.properties?.["$kdsl"]?.const?.NamedType?.Name;
43
+ const resourceType = typeName ? typeName.toLowerCase() : Object.keys(value.properties || {})[0];
44
+ const inner = value.properties?.[resourceType] || value.properties?.inner;
45
+ const defaultValue =
46
+ inner?.default !== undefined
47
+ ? String(inner.default)
48
+ : inner?.enum?.[0]
49
+ ? String(inner.enum[0])
50
+ : undefined;
51
+ resources.push({
52
+ name: key,
53
+ type: resourceType || "string",
54
+ required: resourceProps.required?.includes(key) || false,
55
+ defaultValue,
56
+ });
57
+ }
58
+ });
59
+ }
60
+
61
+ const srvProps = schema.properties?.srv?.properties;
62
+ if (srvProps) {
63
+ (["client", "server", "duplex"] as const).forEach((channelType) => {
64
+ if (srvProps[channelType]?.properties) {
65
+ Object.entries(srvProps[channelType].properties).forEach(([channelName, channelData]: [string, any]) => {
66
+ const port = channelData.properties?.port?.const || channelData.properties?.port?.enum?.[0];
67
+ const protocol = channelData.properties?.protocol?.const || channelData.properties?.protocol?.enum?.[0];
68
+ channels.push({
69
+ name: channelName,
70
+ type: channelType,
71
+ resource: port && protocol ? { type: "port", value: `${protocol}:${port}` } : undefined,
72
+ });
73
+ });
74
+ }
75
+ });
76
+ }
77
+
78
+ return { parameters, resources, channels };
79
+ };
80
+
81
+ if (schemas.length > 0 && schemas[0].oneOf) {
82
+ const processedVariants: any[] = [];
83
+ for (const schemaRef of schemas[0].oneOf) {
84
+ const refKey = schemaRef.$ref?.replace("#/$defs/", "");
85
+ const actualSchema = schemas[0].$defs?.[refKey];
86
+ if (actualSchema) {
87
+ const result = processSchema(actualSchema);
88
+ processedVariants.push({ name: nameKey, roleName, roles, variant: refKey, ...result });
89
+ }
90
+ }
91
+ return {
92
+ parameters: processedVariants[0]?.parameters || [],
93
+ resources: processedVariants[0]?.resources || [],
94
+ channels: processedVariants[0]?.channels || [],
95
+ name: nameKey,
96
+ roleName,
97
+ roles,
98
+ hasVariants: true,
99
+ variants: processedVariants,
100
+ };
101
+ }
102
+
103
+ if (schemas[0]) {
104
+ const result = processSchema(schemas[0]);
105
+ return { ...result, name: nameKey, roleName, roles, hasVariants: false };
106
+ }
107
+
108
+ return { parameters: [], resources: [], channels: [], name: nameKey, roleName, roles, hasVariants: false };
109
+ };
@@ -239,7 +239,9 @@ export const handleResourceEvent = ({
239
239
  if (existingIndex !== -1) {
240
240
  existingResource = tenant.resources[existingIndex];
241
241
  publishUpdate = true;
242
- tenant.resources[existingIndex] = resource;
242
+ tenant.resources[existingIndex] = existingResource.deleting
243
+ ? { ...resource, deleting: true }
244
+ : resource;
243
245
  } else {
244
246
  tenant.resources.push(resource);
245
247
  }
@@ -376,6 +378,22 @@ export const handleVolumeEvent = (
376
378
  hasRequestingServices: false
377
379
  });
378
380
  };
381
+ export const setResourceDeleting = (
382
+ tenantsMap: Map<string, any>,
383
+ tenantName: string,
384
+ resourceName: string,
385
+ resourceType: string,
386
+ ) => {
387
+ const tenant = tenantsMap.get(tenantName);
388
+ if (!tenant) return;
389
+ const index = tenant.resources.findIndex(
390
+ (res: Resource) => res.name === resourceName && res.type === resourceType,
391
+ );
392
+ if (index === -1) return;
393
+ tenant.resources[index] = { ...tenant.resources[index], deleting: true };
394
+ tenantsMap.set(tenantName, tenant);
395
+ };
396
+
379
397
  export const processResourceResult = (
380
398
  result: any,
381
399
  tenantsMap: Map<string, any>,
@@ -159,12 +159,55 @@ const processRolesAndInstances = (
159
159
  return { roles, instances, usedCpu, usedMemory };
160
160
  };
161
161
 
162
+ const getContainerError = (
163
+ revisionStatus: any,
164
+ ): { code: string; message: string; timestamp: string } | null => {
165
+ for (const roleData of Object.values<any>(revisionStatus?.runtime?.roles ?? {})) {
166
+ for (const instanceData of Object.values<any>(roleData.instances ?? {})) {
167
+ for (const container of Object.values<any>(instanceData.containers ?? {})) {
168
+ if (!container.status.ready) {
169
+ return {
170
+ code: container.status.status.waiting?.reason ?? "ContainerNotReady",
171
+ message: container.status.status.waiting?.message ?? "One or more containers are not ready for unknown reasons.",
172
+ timestamp: Date.now().toString(),
173
+ };
174
+ }
175
+ }
176
+ }
177
+ }
178
+ return null;
179
+ };
180
+
181
+ const handleRevisionStatus = (revisionStatus: any) => {
182
+ if (!revisionStatus?.runtime) {
183
+ return revisionStatus?.state;
184
+ }
185
+
186
+ for (const roleData of Object.values<any>(revisionStatus.runtime.roles)) {
187
+ for (const instanceData of Object.values<any>(roleData.instances)) {
188
+ for (const container of Object.values<any>(instanceData.containers ?? {})) {
189
+ if (!container.status.ready) {
190
+ return {
191
+ code: container.status.status.waiting?.reason ?? "ContainerNotReady",
192
+ message: container.status.status.waiting?.message ?? "One or more containers are not ready for unknown reasons.",
193
+ timestamp: Date.now().toString(),
194
+ };
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ return revisionStatus?.state;
201
+ };
202
+
162
203
  const createRevision = (
163
204
  entityId: string,
164
205
  eventData: any,
165
206
  usedCpu: number,
166
207
  usedMemory: number,
167
208
  ): Revision => {
209
+ const containerError = eventData.status?.error ? null : getContainerError(eventData.status);
210
+
168
211
  return {
169
212
  id: entityId,
170
213
  schema: {},
@@ -181,7 +224,7 @@ const createRevision = (
181
224
  cpu: { max: eventData.spec.intensives?.vcpu / 1000 || 0, min: 0 },
182
225
  memory: { max: eventData.spec.intensives?.ram / 1000 || 0, min: 0 },
183
226
  storage: {
184
- max: eventData.spec.intensives?.shared_disk / 1000 || 0,
227
+ max: (eventData.spec.intensives?.volatile_disk / 1000 || 0) + (eventData.spec.intensives?.nrpersistent_disk / 1000 || 0) + (eventData.spec.intensives?.persistent_disk / 1000 || 0),
185
228
  min: 0,
186
229
  },
187
230
  volatileStorage: {
@@ -199,14 +242,13 @@ const createRevision = (
199
242
  },
200
243
  cost: 0,
201
244
  },
202
- status: eventData.status.state,
203
- errorCode: eventData.status?.error ? eventData.status.error.code : "",
204
- errorMsg: eventData.status?.error ? eventData.status.error.message : "",
245
+ status: handleRevisionStatus(eventData.status),
246
+ errorCode: eventData.status?.error ? eventData.status.error.code : containerError?.code === "CrashLoopBackOff" ? containerError.code : "",
247
+ errorMsg: eventData.status?.error ? eventData.status.error.message : containerError?.code === "CrashLoopBackOff" ? containerError.message : "",
205
248
  createdAt:
206
249
  (eventData.status && eventData.status.runtime?.status?.createdAt) || "",
207
250
  };
208
251
  };
209
-
210
252
  const updateServiceWithRevision = (
211
253
  existingService: Service,
212
254
  entityId: string,
@@ -239,13 +281,21 @@ const updateServiceWithRevision = (
239
281
  String(rev.id) === String(entityId) ? newRevision : rev,
240
282
  );
241
283
 
242
- const updatedService: Service = {
243
- ...existingService,
244
- revisions: updatedRevisions,
245
- role: roles.length > 0 ? roles : existingService.role,
246
- usage: newRevision.usage,
247
- startedAt: newRevision.createdAt || existingService.startedAt,
248
- };
284
+ const isCurrentRevision =
285
+ String(existingService.currentRevision) === String(entityId);
286
+
287
+ const updatedService: Service = isCurrentRevision
288
+ ? {
289
+ ...existingService,
290
+ revisions: updatedRevisions,
291
+ role: roles.length > 0 ? roles : existingService.role,
292
+ usage: newRevision.usage,
293
+ startedAt: newRevision.createdAt || existingService.startedAt,
294
+ }
295
+ : {
296
+ ...existingService,
297
+ revisions: updatedRevisions,
298
+ };
249
299
 
250
300
  const deploymentErrorEvent = eventData.status?.error ? updatedService : null;
251
301
 
@@ -262,7 +312,7 @@ const updateEnvironmentConsumption = (
262
312
 
263
313
  servicesMap.forEach((service, svcId) => {
264
314
  if (service.environment === serviceEnvironmentId) {
265
- const currentRevisionKey = `${svcId}-${service.currentRevision}`;
315
+ const currentRevisionKey = `/tenant/${svcId.split('/')[0]}/service/${svcId.split('/')[1]}/revision/${service.currentRevision}`;
266
316
  const currentRevision = revisionsMap.get(currentRevisionKey);
267
317
  if (currentRevision) {
268
318
  totalEnvCpu += currentRevision.usage.limit.cpu.max || 0;
@@ -300,7 +350,7 @@ const updateAccountConsumption = (
300
350
 
301
351
  servicesMap.forEach((service, svcId) => {
302
352
  if (service.account === serviceAccountId) {
303
- const currentRevisionKey = `${svcId}-${service.currentRevision}`;
353
+ const currentRevisionKey = `/tenant/${svcId.split('/')[0]}/service/${svcId.split('/')[1]}/revision/${service.currentRevision}`;
304
354
  const currentRevision = revisionsMap.get(currentRevisionKey);
305
355
  if (currentRevision) {
306
356
  totalAccountCpu += currentRevision.usage.limit.cpu.max || 0;
@@ -338,7 +388,7 @@ export const handleRevisionEvent = ({
338
388
  accountsMap,
339
389
  }: HandleRevisionEventParams): HandleRevisionEventResult => {
340
390
  const serviceId = `${parentParts.tenant}/${parentParts.service}`;
341
- const revisionKey = `${serviceId}-${entityId}`;
391
+ const revisionKey = `${eventData.id.parent.name}/revision/${entityId}`;
342
392
  const { roles, instances, usedCpu, usedMemory } = processRolesAndInstances(
343
393
  eventData,
344
394
  serviceId,
@@ -646,7 +696,6 @@ export const processRevisionData = (
646
696
  : {};
647
697
  const schema =
648
698
  schemaResult && "parameters" in schemaResult ? schemaResult : {};
649
-
650
699
  if (
651
700
  revisionsMap &&
652
701
  serviceId &&
@@ -654,7 +703,8 @@ export const processRevisionData = (
654
703
  "parameters" in schema
655
704
  ) {
656
705
  const revisionId: string = revisionData.revision;
657
- const revisionKey = `${serviceId}-${revisionId}`;
706
+ const [tenantId, serviceName] = serviceId.split('/');
707
+ const revisionKey = `/tenant/${tenantId}/service/${serviceName}/revision/${revisionId}`;
658
708
  const existing = revisionsMap.get(revisionKey);
659
709
  if (existing) {
660
710
  revisionsMap.set(revisionKey, { ...existing, schema });
@@ -675,7 +725,7 @@ export const processRevisionData = (
675
725
  cpu: { max: revisionData.intensives?.vcpu / 1000 || 0, min: 0 },
676
726
  memory: { max: revisionData.intensives?.ram / 1000 || 0, min: 0 },
677
727
  storage: {
678
- max: revisionData.intensives?.shared_disk / 1000 || 0,
728
+ max: (revisionData.intensives?.volatile_disk / 1000 || 0) + (revisionData.intensives?.nrpersistent_disk / 1000 || 0) + (revisionData.intensives?.persistent_disk / 1000 || 0),
679
729
  min: 0,
680
730
  },
681
731
  volatileStorage: {