import { errors, Notification, Registry, Tenant, tenantRole } from "@kumori/aurora-interfaces"; import { eventHelper } from "../backend-handler"; import { environment } from "../environment"; import { initializeGlobalWebSocketClient, getWebSocketStatus, makeGlobalWebSocketRequest, } from "../websocket-manager"; type Security = string; interface DregistryBody { spec: { labels?: { [key: string]: string }; docker_server: string; docker_username: string; docker_password: string; }; } /** * Function to create a tenant using the global WebSocket connection * @param tenant Tenant object with the data of the tenant * @param security Authorization token * @returns The response of the WebSocket API */ export const createTenant = async (tenant: Tenant, security: Security) => { try { await initializeGlobalWebSocketClient(security); const tenantBody = tenant.npmRegistry && tenant.npmRegistry.endpoint !== "" ? { tenant: tenant.name, provider: tenant.plan?.provider || "", plan: tenant.plan?.name || "", spec: { registry: { kind: "git", endpoint: tenant.npmRegistry.endpoint, domain: tenant.npmRegistry.domain, credentials: tenant.npmRegistry.credentials, public: tenant.npmRegistry.public, }, }, } : { tenant: tenant.name, provider: tenant.plan?.provider || "", plan: tenant.plan?.name || "", spec: { registry: undefined, }, }; const response = await makeGlobalWebSocketRequest( "tenant:create_tenant", tenantBody, 30000, "CREATE", tenant.name ); const updatedTenant = { ...tenant, status: "pending" }; eventHelper.tenant.publish.created(updatedTenant); const tenantCreatedNotification: Notification = { type: "success", subtype: errors.tenant.created.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, }; eventHelper.notification.publish.creation(tenantCreatedNotification); return response; } catch (error) { console.error("Error creating tenant:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenant.name, webSocketStatus: getWebSocketStatus(), }); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const tenantCreationErrorNotification: Notification = { type: "error", subtype: errors.tenant.creationError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, userError: true, }; eventHelper.notification.publish.creation(tenantCreationErrorNotification); throw error; } }; export const deleteTenant = async (tenant: Tenant, security: string) => { try { await initializeGlobalWebSocketClient(security); const deleteBody = { tenant: tenant.name, force: true, }; const response = await makeGlobalWebSocketRequest( "tenant:delete_tenant", deleteBody, 30000, "DELETE", tenant.name ); // const updatedTenant = { ...tenant, status: "pending" }; // eventHelper.tenant.publish.deleted(updatedTenant); // const tenantDeletedNotification: Notification = { // type: "success", // subtype: "tenant-deleted", // date: Date.now().toString(), // status: "unread", // callToAction: false, // }; // eventHelper.notification.publish.creation(tenantDeletedNotification); return response; } catch (err) { console.error("Error in tenant deletion WebSocket request:", err); eventHelper.tenant.publish.deletionError(tenant); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof err === "object" && err !== null && "error" in err && typeof (err as any).error === "object" && (err as any).error !== null ) { if ("code" in (err as any).error) { contentMessage = (err as any).error.code; } if ("content" in (err as any).error) { errorContent = (err as any).error.content; } } const tenantDeletionErrorNotification: Notification = { type: "error", subtype: errors.tenant.deletionError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, userError: true, }; eventHelper.notification.publish.creation(tenantDeletionErrorNotification); throw err; } }; export const updateTenant = async (tenant: Tenant, security: string) => { try { await initializeGlobalWebSocketClient(security); const hasNpmRegistry = tenant.npmRegistry !== undefined && tenant.npmRegistry !== null; const isNpmRegistryEmpty = hasNpmRegistry && tenant.npmRegistry!.endpoint === "" && tenant.npmRegistry!.domain === "" && tenant.npmRegistry!.credentials === "" && tenant.npmRegistry!.public === false; const hasPlan = tenant.plan?.name; const updateBody: Record = { tenant: tenant.name, spec: { registry: !hasNpmRegistry ? undefined : isNpmRegistryEmpty ? null : { kind: "git", endpoint: tenant.npmRegistry!.endpoint, domain: tenant.npmRegistry!.domain, credentials: tenant.npmRegistry!.credentials, public: tenant.npmRegistry!.public, }, }, }; if (hasPlan) { updateBody.provider = tenant.plan!.provider || ""; updateBody.plan = tenant.plan!.name; } const response = await makeGlobalWebSocketRequest( "tenant:update_tenant", updateBody, 30000, "UPDATE", tenant.name ); const updatedTenant = { ...tenant, status: "pending" }; eventHelper.tenant.publish.updated(updatedTenant); const tenantCreatedNotification: Notification = { type: "success", subtype: errors.tenant.updated.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, }; eventHelper.notification.publish.creation(tenantCreatedNotification); return response; } catch (err) { console.error("Error in tenant update WebSocket request:", err); eventHelper.tenant.publish.updateError(tenant); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof err === "object" && err !== null && "error" in err && typeof (err as any).error === "object" && (err as any).error !== null ) { if ("code" in (err as any).error) { contentMessage = (err as any).error.code; } if ("content" in (err as any).error) { errorContent = (err as any).error.content; } } const tenantUpdateErrorNotification: Notification = { type: "error", subtype: errors.tenant.updateError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, userError: true, }; eventHelper.notification.publish.creation(tenantUpdateErrorNotification); throw err; } }; /** * Function to create a tenant * @param tenant Tenant object with the data of the tenant * @returns The response of the API. */ export const createTenantHTTP = async (tenant: Tenant) => { const createTenantUrl = new URL( `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${tenant.name}` ); if (tenant.plan && tenant.plan?.name !== "" && tenant.plan?.provider !== "") { createTenantUrl.searchParams.append("plan", tenant.plan?.name || ""); createTenantUrl.searchParams.append( "provider", tenant.plan?.provider || "" ); } const tenantBody = tenant.npmRegistry && tenant.npmRegistry.endpoint !== "" ? { tenant: tenant.name, provider: tenant.plan?.provider || "", plan: tenant.plan?.name || "", spec: { registry: { kind: "git", endpoint: tenant.npmRegistry.endpoint, domain: tenant.npmRegistry.domain, credentials: tenant.npmRegistry.credentials, public: tenant.npmRegistry.public, }, }, } : { tenant: tenant.name, spec: { registry: undefined, }, }; const response = await fetch(createTenantUrl, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(tenantBody), }); if (response.ok) { const updatedTenant = { ...tenant, status: "pending" }; eventHelper.tenant.publish.created(updatedTenant); const tenantCreatedNotification: Notification = { type: "success", subtype: errors.tenant.created.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, }; eventHelper.notification.publish.creation(tenantCreatedNotification); } else { eventHelper.tenant.publish.creationError(tenant); let errorCode = "Unknown error"; let errorMessage = "Unknown error"; try { const errorBody = await response.json(); if (errorBody?.code) { errorCode = errorBody.code; } if (errorBody?.content) { errorMessage = errorBody.content; } else { errorMessage = JSON.stringify(errorBody, null, 2); } } catch (e) { const text = await response.text(); errorMessage = text || "Unknown error"; } const tenantCreationErrorNotification: Notification = { type: "error", subtype: errors.tenant.creationError.subtype, info_content: { code: errorCode, message: errorMessage, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, userError: true, }; eventHelper.notification.publish.creation(tenantCreationErrorNotification); } }; export const deleteTenantHTTP = async (tenant: Tenant) => { const url = new URL( `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${tenant.name}` ); url.searchParams.append("force", "true"); const response = await fetch(url.toString(), { method: "DELETE", }); if (response.ok) { const tenantDeletedNotification: Notification = { type: "success", subtype: errors.tenant.deleting.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, }; eventHelper.notification.publish.creation(tenantDeletedNotification); } else { eventHelper.tenant.publish.deletionError(tenant); let errorCode = "Unknown error"; let errorMessage = "Unknown error"; try { const errorBody = await response.json(); if (errorBody?.code) { errorCode = errorBody.code; } if (errorBody?.content) { errorMessage = errorBody.content; } } catch (e) { const text = await response.text(); errorMessage = text || "Unknown error"; } const tenantDeletionErrorNotification: Notification = { type: "error", subtype: errors.tenant.deletionError.subtype, info_content: { code: errorCode, message: errorMessage, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, userError: true, }; eventHelper.notification.publish.creation(tenantDeletionErrorNotification); } }; export const updateTenantHTTP = async (tenant: Tenant) => { const updateTenantUrl = new URL( `${environment.apiServer.baseUrl}/api/${environment.apiServer.apiVersion}/tenant/${tenant.name}` ); if (tenant.plan && tenant.plan?.name !== "" && tenant.plan?.provider !== "") { updateTenantUrl.searchParams.append("plan", tenant.plan?.name || ""); updateTenantUrl.searchParams.append( "provider", tenant.plan?.provider || "" ); } const tenantBody = tenant.npmRegistry && tenant.npmRegistry.endpoint !== "" ? { tenant: tenant.name, provider: tenant.plan?.provider || "", plan: tenant.plan?.name || "", spec: { registry: { kind: "git", endpoint: tenant.npmRegistry.endpoint, domain: tenant.npmRegistry.domain, credentials: tenant.npmRegistry.credentials, public: tenant.npmRegistry.public, }, }, } : { tenant: tenant.name, spec: { registry: undefined, }, }; const response = await fetch(updateTenantUrl, { method: "PATCH", headers: { "Content-Type": "application/json", }, body: JSON.stringify(tenantBody), }); if (response.ok) { const updatedTenant = { ...tenant, status: "pending" }; eventHelper.tenant.publish.updated(updatedTenant); const tenantCreatedNotification: Notification = { type: "success", subtype: errors.tenant.updated.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, }; eventHelper.notification.publish.creation(tenantCreatedNotification); } else { eventHelper.tenant.publish.updateError(tenant); let errorCode = "Unknown error"; let errorMessage = "Unknown error"; try { const errorBody = await response.json(); if (errorBody?.code) { errorCode = errorBody.code; } if (errorBody?.content) { errorMessage = errorBody.content; } } catch (e) { const text = await response.text(); errorMessage = text || "Unknown error"; } const tenantUpdateErrorNotification: Notification = { type: "error", subtype: errors.tenant.updateError.subtype, info_content: { code: errorCode, message: errorMessage, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, userError: true, }; eventHelper.notification.publish.creation(tenantUpdateErrorNotification); } }; export const createRegistry = async ( tenant: Tenant, security: Security, registry: Registry ) => { try { await initializeGlobalWebSocketClient(security); const dregistryBody: DregistryBody = { spec: { labels: { logo: registry.extra }, docker_server: registry.domain, docker_username: registry.credentials, docker_password: registry.password || "", }, }; const queryParams = { tenant: tenant.name, dregistry: registry.name, }; const response = await makeGlobalWebSocketRequest( "dregistry:create_dregistry", { ...dregistryBody, ...queryParams, }, 30000, "CREATE", `${tenant.name}/${registry.domain}` ); const dregistryCreatedNotification: Notification = { type: "success", subtype: errors.registry.created.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { registry: registry.name, tenant: tenant.name, }, }; eventHelper.notification.publish.creation(dregistryCreatedNotification); return response; } catch (error) { console.error("Error creating dregistry:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenant.name, registry: registry.domain, webSocketStatus: getWebSocketStatus(), }); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const dregistryCreationErrorNotification: Notification = { type: "error", subtype: errors.registry.creationError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, userError: true, }; eventHelper.notification.publish.creation( dregistryCreationErrorNotification ); throw error; } }; /** * Function to update a dregistry using the global WebSocket connection * @param tenant Tenant object with registry information * @param security Authorization token * @param force Force update flag (default: false) * @returns The response of the WebSocket API */ export const updateRegistry = async ( tenant: Tenant, registry: Registry, security: Security, force: boolean = false ) => { try { await initializeGlobalWebSocketClient(security); const dregistryBody: DregistryBody = { spec: { labels: { logo: registry.extra }, docker_server: registry.domain, docker_username: registry.credentials, docker_password: registry.password || "", }, }; const queryParams = { tenant: tenant.name, dregistry: registry.name, force: force, }; const response = await makeGlobalWebSocketRequest( "dregistry:update_dregistry", { ...dregistryBody, ...queryParams, }, 30000, "UPDATE", `${tenant.name}/${registry.domain}` ); const dregistryUpdatedNotification: Notification = { type: "success", subtype: errors.registry.updated.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { registry: registry.name, tenant: tenant.name, }, }; eventHelper.notification.publish.creation(dregistryUpdatedNotification); return response; } catch (error) { console.error("Error updating dregistry:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenant.name, registry: registry.domain, force, webSocketStatus: getWebSocketStatus(), }); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const dregistryUpdateErrorNotification: Notification = { type: "error", subtype: errors.registry.updateError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, userError: true, }; eventHelper.notification.publish.creation(dregistryUpdateErrorNotification); throw error; } }; export const deleteRegistry = async ( tenant: Tenant, registry: Registry, security: Security, force: boolean = false ) => { try { await initializeGlobalWebSocketClient(security); const queryParams = { tenant: tenant.name, dregistry: registry.name, force: force, }; const response = await makeGlobalWebSocketRequest( "dregistry:delete_dregistry", queryParams, 30000, "DELETE", `${tenant.name}/${registry.domain}` ); const dregistryDeletedNotification: Notification = { type: "success", subtype: errors.registry.deleted.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { registry: registry.name, tenant: tenant.name, }, }; eventHelper.notification.publish.creation(dregistryDeletedNotification); return response; } catch (error) { console.error("Error deleting dregistry:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenant.name, registry: registry.domain, force, webSocketStatus: getWebSocketStatus(), }); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const dregistryDeletionErrorNotification: Notification = { type: "error", subtype: errors.registry.deletionError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant.name, }, userError: true, }; eventHelper.notification.publish.creation( dregistryDeletionErrorNotification ); throw error; } }; export const inviteUser = async ( tenant: string, email: string, role: tenantRole, security: string ) => { try { await initializeGlobalWebSocketClient(security); const queryParams = { tenant: tenant, user: email, role: role, }; const response = await makeGlobalWebSocketRequest( "tenant:propose_user", queryParams, 30000, "CREATE", `${tenant}/${email}` ); const tenantInvitedNotification: Notification = { type: "success", subtype: errors.tenant.userInvited.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, email: email, role, tenantRole, }, }; eventHelper.notification.publish.creation(tenantInvitedNotification); return response; } catch (error) { console.error("Error inviting user:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenant, email: email, role: role, webSocketStatus: getWebSocketStatus(), }); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const tenantInviteErrorNotification: Notification = { type: "error", subtype: errors.tenant.userInviteError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, email: email, role, tenantRole, }, userError: true, }; eventHelper.notification.publish.creation(tenantInviteErrorNotification); throw error; } }; export const removeUser = async ( tenant: string, userId: string, security: string ) => { try { await initializeGlobalWebSocketClient(security); const queryParams = { tenant: tenant, user: userId, }; const response = await makeGlobalWebSocketRequest( "tenant:exclude_user", queryParams, 30000, "DELETE", `${tenant}/${userId}` ); const tenantUserRemovedNotification: Notification = { type: "success", subtype: errors.tenant.userRemoved.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, user: userId, }, }; eventHelper.notification.publish.creation(tenantUserRemovedNotification); return response; } catch (error) { console.error("Error removing user from tenant:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenant, userId: userId, webSocketStatus: getWebSocketStatus(), }); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const tenantUserRemovedErrorNotification: Notification = { type: "error", subtype: errors.tenant.userRemovedError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, user: userId, }, userError: true, }; eventHelper.notification.publish.creation( tenantUserRemovedErrorNotification ); throw error; } }; export const updateUserRole = async ( tenant: string, userId: string, role: tenantRole, security: string ) => { try { await initializeGlobalWebSocketClient(security); const queryParams = { tenant: tenant, user: userId, role: role, }; const response = await makeGlobalWebSocketRequest( "tenant:modify_user_role", queryParams, 30000, "PATCH", `${tenant}/${userId}` ); const tenantUserUpdatedNotification: Notification = { type: "success", subtype: errors.tenant.roleUpdated.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, user: userId, role: role, }, }; eventHelper.notification.publish.creation(tenantUserUpdatedNotification); return response; } catch (error) { console.error("Error updating user in tenant:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenant, userId: userId, role: role, webSocketStatus: getWebSocketStatus(), }); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const tenantUserUpdatedErrorNotification: Notification = { type: "error", subtype: errors.tenant.roleUpdateError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, user: userId, role: role, }, userError: true, }; eventHelper.notification.publish.creation( tenantUserUpdatedErrorNotification ); throw error; } }; export const acceptInvite = async (tenant: string, security: string) => { try { await initializeGlobalWebSocketClient(security); const queryParams = { tenant: tenant }; const response = await makeGlobalWebSocketRequest( "tenant:accept_proposal_user", queryParams, 30000, "PUT", `${tenant}/accept` ); const tenantInviteAcceptedNotification: Notification = { type: "success", subtype: errors.tenant.inviteAccepted.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, }, }; eventHelper.notification.publish.creation(tenantInviteAcceptedNotification); return response; } catch (error) { console.error("Error accepting tenant invite:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenant, webSocketStatus: getWebSocketStatus(), }); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const tenantInviteAcceptedErrorNotification: Notification = { type: "error", subtype: errors.tenant.inviteAcceptError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, }, userError: true, }; eventHelper.notification.publish.creation( tenantInviteAcceptedErrorNotification ); throw error; } }; export const rejectInvite = async (tenant: string, security: string, leave: boolean) => { try { await initializeGlobalWebSocketClient(security); const queryParams = { tenant: tenant }; const response = await makeGlobalWebSocketRequest( "tenant:reject_proposal_user", queryParams, 30000, "REJECT", `${tenant}/reject` ); if(leave){ const tenantInviteRejectedNotification: Notification = { type: "success", subtype: errors.tenant.leave.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, }, }; eventHelper.notification.publish.creation(tenantInviteRejectedNotification); } else{ const tenantInviteRejectedNotification: Notification = { type: "success", subtype: errors.tenant.inviteRejected.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, }, }; eventHelper.notification.publish.creation(tenantInviteRejectedNotification); } return response; } catch (error) { console.error("Error rejecting tenant invite:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenant, webSocketStatus: getWebSocketStatus(), }); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const tenantInviteRejectedErrorNotification: Notification = { type: "error", subtype: errors.tenant.inviteRejectError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenant, }, userError: true, }; eventHelper.notification.publish.creation( tenantInviteRejectedErrorNotification ); throw error; } }; export const createToken = async ( tenantName: string, tokenDescription: string, tokenExpiration: string, security: string ) => { try { await initializeGlobalWebSocketClient(security); const createTokenBody = { spec: { scopes: { tenant: { [tenantName]: { allow: ["*:*:*"] } }, planprovider: { "*": { allow: ["*:*:*"] } }, user: { "*": { allow: ["*:*:*"] } }, idprovider: { "*": { allow: ["*:*:*"] } }, }, expiration: tokenExpiration, description: tokenDescription, labels: { tenant: tenantName, }, }, }; const response = await makeGlobalWebSocketRequest( "token:create_token", createTokenBody, 30000, "CREATE", `${tenantName}/tokens`, "token" ); const tenantTokenCreatedNotification: Notification = { type: "success", subtype: errors.user.tokenCreated.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { tenant: tenantName, tokenName: tokenDescription, }, }; eventHelper.notification.publish.creation(tenantTokenCreatedNotification); return response; } catch (error) { console.error("Error creating tenant token:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenantName, webSocketStatus: getWebSocketStatus(), }); throw error; } }; export const deleteToken = async ( tenantName: string, tokenID: string, security: string ) => { try { await initializeGlobalWebSocketClient(security); const queryParams = { token_jti: tokenID, }; const response = await makeGlobalWebSocketRequest( "token:revoke_token", queryParams, 30000, "DELETE", `${tenantName}/tokens/${tokenID}` ); return response; } catch (error) { console.error("Error deleting tenant token:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", tenant: tenantName, webSocketStatus: getWebSocketStatus(), }); throw error; } };