@kumori/aurora-backend-handler 1.0.100 → 1.0.112

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, getWuiErrorCode, 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 = {
@@ -288,7 +292,7 @@ export const handleAccountOperationSuccess = ({
288
292
  subtype: "account-deleted",
289
293
  date: Date.now().toString(),
290
294
  status: "unread",
291
- callToAction: false,
295
+ notificationType: "regular",
292
296
  data: { account: originalData.name, tenant: originalData.tenant },
293
297
  },
294
298
  eventType: "deleted",
@@ -307,7 +311,7 @@ export const handleAccountOperationSuccess = ({
307
311
  subtype: isCreate ? "account-created" : "account-updated",
308
312
  date: Date.now().toString(),
309
313
  status: "unread",
310
- callToAction: false,
314
+ notificationType: "regular",
311
315
  data: { account: updatedAccount.name, tenant: updatedAccount.tenant },
312
316
  },
313
317
  eventType: isCreate ? "created" : "updated",
@@ -322,7 +326,7 @@ export const handleAccountOperationSuccess = ({
322
326
  subtype: "account-unknown",
323
327
  date: Date.now().toString(),
324
328
  status: "unread",
325
- callToAction: false,
329
+ notificationType: "regular",
326
330
  data: {},
327
331
  },
328
332
  eventType: null,
@@ -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,11 @@ export const handleAccountOperationError = ({
359
357
  const errorCode: string = error?.error?.code ?? error?.code ?? "";
360
358
  const errorStatus = resolveErrorStatus(errorCode);
361
359
 
360
+ const errSubtype = isCreate ? "account-creation-error" : isUpdate ? "account-update-error" : "account-deletion-error";
361
+ const errMethod = isCreate ? "createAccount" : isUpdate ? "updateAccount" : "deleteAccount";
362
362
  const notification: Notification = {
363
363
  type: "error",
364
- subtype,
364
+ subtype: getWuiErrorCode("account", errMethod, errorCode) ?? errSubtype,
365
365
  date: Date.now().toString(),
366
366
  status: "unread",
367
367
  info_content: {
@@ -370,7 +370,7 @@ export const handleAccountOperationError = ({
370
370
  error?.error?.content ?? error?.error?.message ?? "Unknown error",
371
371
  timestamp: error?.error?.timestamp ?? Date.now().toString(),
372
372
  },
373
- callToAction: false,
373
+ notificationType: "regular",
374
374
  data: {
375
375
  account:
376
376
  entityName || originalData?.name || originalData?.account || "unknown",
@@ -1,4 +1,4 @@
1
- import { Account, Environment, Notification } from "@kumori/aurora-interfaces";
1
+ import { Account, Environment, getWuiErrorCode, 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: {
@@ -184,7 +187,7 @@ export const handleEnvironmentOperationSuccess = ({
184
187
  subtype: "environment-cleaned",
185
188
  date: Date.now().toString(),
186
189
  status: "unread",
187
- callToAction: false,
190
+ notificationType: "regular",
188
191
  data: {
189
192
  environment: envData.name,
190
193
  account: envData.account,
@@ -240,23 +243,17 @@ 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 envErrSubtype = action === "CREATE" ? "environment-creation-error" : action === "UPDATE" ? "environment-update-error" : "environment-deletion-error";
253
+ const envErrMethod = action === "CREATE" ? "createEnvironment" : action === "UPDATE" ? "updateEnvironment" : "deleteEnvironment";
257
254
  const envErrorNotification: Notification = {
258
255
  type: "error",
259
- subtype,
256
+ subtype: getWuiErrorCode("environment", envErrMethod, error?.error?.code || "UNKNOWN_ERROR") ?? envErrSubtype,
260
257
  date: Date.now().toString(),
261
258
  status: "unread",
262
259
  info_content: {
@@ -264,7 +261,7 @@ export const handleEnvironmentOperationError = ({
264
261
  message: error?.error?.content || error?.error?.message || "Unknown error",
265
262
  timestamp: error?.error?.timestamp || "",
266
263
  },
267
- callToAction: false,
264
+ notificationType: "regular",
268
265
  data: {
269
266
  environment: originalData.name,
270
267
  account: originalData.account,
@@ -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: {