fix(collab): fix self-lockout, stuck live sessions, block locking propagation and reactive hashtags
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 58s

This commit is contained in:
sandrodach committed 2026-10-27 14:57:30 +01:00
1 parent 0e06cc5577
commit 996f27133c
6 files changed
+303 -89

No files matched your search

+23 -10
View File
@@ -40,6 +40,19 @@ export function getToken(): string | null {
return localStorage.getItem(TOKEN_STORAGE_KEY);
}
export function getCurrentUserId(): string | null {
const token = getToken();
if (!token) return null;
try {
const parts = token.split('.');
if (parts.length >= 2) {
const payload = JSON.parse(atob(parts[1]));
return payload.userId || payload.sub || payload.id || null;
}
} catch {}
return null;
}
export function setToken(token: string): void {
localStorage.setItem(TOKEN_STORAGE_KEY, token);
}
@@ -637,10 +650,11 @@ export const api = {
},
async lockBlock(docId: string, blockId: string, userColor?: string, ttlSeconds: number = 30): Promise<BlockLockInfo> {
return request<BlockLockInfo>(`/api/v1/documents/${docId}/blocks/${encodeURIComponent(blockId)}/lock`, {
const res = await request<any>(`/api/v1/documents/${docId}/blocks/${encodeURIComponent(blockId)}/lock`, {
method: 'POST',
body: JSON.stringify({ userColor, ttlSeconds }),
});
return res?.lock || res;
},
async unlockBlock(docId: string, blockId: string): Promise<{ status: string }> {
@@ -650,9 +664,10 @@ export const api = {
},
async startLiveSession(docId: string): Promise<LiveSessionInfo> {
return request<LiveSessionInfo>(`/api/v1/documents/${docId}/live/start`, {
const res = await request<any>(`/api/v1/documents/${docId}/live/start`, {
method: 'POST',
});
return res?.session || res;
},
async endLiveSession(docId: string): Promise<{ status: string }> {
@@ -1442,10 +1457,9 @@ export function createRealtimeConnection(options: {
// Join rooms on the active connection
const joinAll = () => {
joinedRooms.forEach((r) => {
if (r.startsWith('doc:')) {
sendWebSocketMessage({ event: 'CRDT_JOIN', docId: r.slice(4) });
} else {
sendWebSocketMessage({ event: 'JOIN_ROOM', room: r });
sendWebSocketMessage({ event: 'JOIN_ROOM', room: r });
if (activeSSEId) {
api.joinSSERoom(activeSSEId, r, 'join').catch(() => {});
}
});
};
@@ -1475,10 +1489,9 @@ export function createRealtimeConnection(options: {
if (unsubMsg) unsubMsg();
joinedRooms.forEach((r) => {
globalSubscribedRooms.delete(r);
if (r.startsWith('doc:')) {
sendWebSocketMessage({ event: 'CRDT_LEAVE', docId: r.slice(4) });
} else {
sendWebSocketMessage({ event: 'LEAVE_ROOM', room: r });
sendWebSocketMessage({ event: 'LEAVE_ROOM', room: r });
if (activeSSEId) {
api.joinSSERoom(activeSSEId, r, 'leave').catch(() => {});
}
});
},