diff --git a/platforms/cerberus/src/controllers/WebhookController.ts b/platforms/cerberus/src/controllers/WebhookController.ts index d16c0116..0657712a 100644 --- a/platforms/cerberus/src/controllers/WebhookController.ts +++ b/platforms/cerberus/src/controllers/WebhookController.ts @@ -175,16 +175,15 @@ export class WebhookController { // Only process if there's actually a charter change, not just a message update if (newCharter !== undefined && newCharter !== null && oldCharter !== newCharter) { - try { - await this.cerberusTriggerService.processCharterChange( - group.id, - group.name, - oldCharter, - newCharter - ); - } catch (error) { + // Don't await - let it run asynchronously to avoid blocking webhook response + this.cerberusTriggerService.processCharterChange( + group.id, + group.name, + oldCharter, + newCharter + ).catch((error) => { console.error("Error in processCharterChange:", error); - } + }); } } else { // Check if group already exists by ename (only if ename is available) @@ -223,16 +222,15 @@ export class WebhookController { // Check if new group has a charter and send Cerberus welcome message if (group.charter) { - try { - await this.cerberusTriggerService.processCharterChange( - group.id, - group.name, - undefined, // No old charter for new groups - group.charter - ); - } catch (error) { + // Don't await - let it run asynchronously to avoid blocking webhook response + this.cerberusTriggerService.processCharterChange( + group.id, + group.name, + undefined, // No old charter for new groups + group.charter + ).catch((error) => { console.error("Error in processCharterChange for new group:", error); - } + }); } } } diff --git a/platforms/group-charter-manager-api/src/controllers/GroupController.ts b/platforms/group-charter-manager-api/src/controllers/GroupController.ts index e9c03b2b..c6664842 100644 --- a/platforms/group-charter-manager-api/src/controllers/GroupController.ts +++ b/platforms/group-charter-manager-api/src/controllers/GroupController.ts @@ -2,6 +2,7 @@ import { Request, Response } from "express"; import { GroupService } from "../services/GroupService"; import { CharterSignatureService } from "../services/CharterSignatureService"; import { spinUpEVault } from "web3-adapter"; +import { adapter } from "../web3adapter"; import dotenv from "dotenv"; dotenv.config(); @@ -27,6 +28,9 @@ export class GroupController { participants: [] }); + // Lock the group so it doesn't sync until charter+ename are added + adapter.addToLockedIds(group.id); + // Add participants including the creator const allParticipants = [...new Set([userId, ...participants])]; for (const participantId of allParticipants) { @@ -142,6 +146,14 @@ export class GroupController { updateData.ename = evaultResult.w3id; } + // Unlock the group so it CAN sync now that it has charter+ename + if (needsEVault) { + const lockIndex = adapter.lockedIds.indexOf(id); + if (lockIndex > -1) { + adapter.lockedIds.splice(lockIndex, 1); + } + } + // Now save with both charter and ename (if provisioned) const updatedGroup = await this.groupService.updateGroup(id, updateData); @@ -149,6 +161,26 @@ export class GroupController { return res.status(404).json({ error: "Group not found" }); } + // HACK: Manually trigger sync after delay to ensure complete data is sent + if (needsEVault) { + setTimeout(async () => { + try { + // Re-fetch the complete group entity with all relations + const completeGroup = await this.groupService.getGroupById(id); + if (completeGroup && completeGroup.charter && completeGroup.ename) { + // Convert to plain object and trigger the adapter manually + const plainGroup = JSON.parse(JSON.stringify(completeGroup)); + await adapter.handleChange({ + data: plainGroup, + tableName: "groups" + }); + } + } catch (error) { + console.error("Error in manual sync:", error); + } + }, 5000); // 5 second delay + } + res.json(updatedGroup); } catch (error) { console.error("Error updating charter:", error); diff --git a/platforms/group-charter-manager-api/src/services/GroupService.ts b/platforms/group-charter-manager-api/src/services/GroupService.ts index 746c8031..bf9793cb 100644 --- a/platforms/group-charter-manager-api/src/services/GroupService.ts +++ b/platforms/group-charter-manager-api/src/services/GroupService.ts @@ -28,29 +28,24 @@ export class GroupService { } async updateGroup(id: string, groupData: Partial): Promise { - // If updating the charter, we need to delete all existing signatures - // since the charter content has changed - if (groupData.charter !== undefined) { - // Get the current group to check if charter is being updated - const currentGroup = await this.getGroupById(id); - if (currentGroup && currentGroup.charter !== groupData.charter) { - // Charter content has changed, so delete all existing signatures - console.log(`Charter updated for group ${id}, deleting all existing signatures`); - await this.charterSignatureService.deleteAllSignaturesForGroup(id); - } - } - // Get the current group, merge the data, and save it to trigger ORM events const currentGroup = await this.getGroupById(id); if (!currentGroup) { throw new Error("Group not found"); } + // Check if charter is being updated/added to delete signatures BEFORE saving + const charterChanged = groupData.charter !== undefined && currentGroup.charter !== groupData.charter; + if (charterChanged) { + await this.charterSignatureService.deleteAllSignaturesForGroup(id); + } + // Merge the new data with the existing group Object.assign(currentGroup, groupData); - // Save the merged group to trigger ORM subscribers + // Save the merged group to trigger ORM subscribers - ONE save with all data const updatedGroup = await this.groupRepository.save(currentGroup); + return updatedGroup; } diff --git a/platforms/group-charter-manager-api/src/web3adapter/watchers/subscriber.ts b/platforms/group-charter-manager-api/src/web3adapter/watchers/subscriber.ts index ecd06bc6..62a1b095 100644 --- a/platforms/group-charter-manager-api/src/web3adapter/watchers/subscriber.ts +++ b/platforms/group-charter-manager-api/src/web3adapter/watchers/subscriber.ts @@ -200,6 +200,11 @@ export class PostgresSubscriber implements EntitySubscriberInterface { // Handle regular entity changes const data = this.entityToPlain(entity); if (!data.id) return; + + // Skip groups without charter - they'll be manually synced when charter is added + if (tableName === "groups" && !data.charter) { + return; + } try { setTimeout(async () => {