fix(channels): newly created channel sometimes hidden until space reopened

The sidebar's visibleChannels filter is keyed on the channelPermissions
Map. Creating a channel raced two state updates: the optimistic create
(added to channels with no permission entry) and the channel_created WS
event (the only thing that set the permission). When the optimistic add
won the race, the WS handler hit its dedup guard, skipped setChannels,
and set the permission by mutating the Map in place — no new reference,
so visibleChannels never recomputed and the channel stayed hidden until
loadSpace rebuilt the maps (i.e. leaving and returning to the space).

Centralize the logic in a new upsertChannel store action that replaces
channels and channelPermissions with fresh references, used by both the
create path and the channel_created handler. Also return the creator's
computed myPermissions (and isPrivate) from POST so the channel renders
immediately from the response, independent of WS timing.

Adds spaceStore.upsertChannel.test.ts covering the reference-identity
regression and the optimistic-reconcile path.
This commit is contained in:
Jannis Braun
2026-06-25 12:34:11 +02:00
parent a4af708a41
commit 00a2876e96
5 changed files with 163 additions and 19 deletions
+9 -1
View File
@@ -254,7 +254,15 @@ export async function channelRoutes(app: FastifyInstance): Promise<void> {
}
}
return reply.code(201).send(channelData);
// Return the channel with the creator's computed permissions (same shape as
// the channel_created WS event) so the client can render it immediately
// without waiting for the broadcast to round-trip.
const creatorPerms = computePermissions(request.userId, id, channelId);
return reply.code(201).send({
...channelData,
isPrivate: false,
myPermissions: permissionsToString(creatorPerms),
});
});
// PATCH /api/channels/:id - Update a channel (admin+)