Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions apps/ui/src/lib/http-api-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2763,6 +2763,21 @@ export class HttpApiClient implements ElectronAPI {
headers?: Record<string, string>;
enabled?: boolean;
}>;
eventHooks?: Array<{
id: string;
trigger: string;
enabled: boolean;
action: Record<string, unknown>;
name?: string;
}>;
ntfyEndpoints?: Array<{
id: string;
name: string;
serverUrl: string;
topic: string;
authType: string;
enabled: boolean;
}>;
};
error?: string;
}> => this.get('/api/settings/global'),
Expand Down
5 changes: 4 additions & 1 deletion apps/ui/src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,10 @@ function RootLayoutContent() {
// Reconcile ntfy endpoints from server (same rationale as eventHooks)
const serverEndpoints = (finalSettings as GlobalSettings).ntfyEndpoints ?? [];
const currentEndpoints = useAppStore.getState().ntfyEndpoints;
if (JSON.stringify(serverEndpoints) !== JSON.stringify(currentEndpoints)) {
if (
JSON.stringify(serverEndpoints) !== JSON.stringify(currentEndpoints) &&
serverEndpoints.length > 0
) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This change introduces a potential data synchronization issue for ntfyEndpoints, and a similar issue already exists for eventHooks on lines 603-606.

The condition serverEndpoints.length > 0 is likely intended to prevent an uninitialized empty array from the server from wiping the client's state. However, it also prevents syncing a deliberately cleared list of endpoints. If a user deletes all endpoints on one device, other clients will fail to sync this change and will retain a stale list.

Given that app-store.ts now sends a special flag (__allowEmpty...) when clearing endpoints, we can be more confident that an empty array from the server is an intentional state.

To ensure correct synchronization, this length check should be removed.

                  if (JSON.stringify(serverEndpoints) !== JSON.stringify(currentEndpoints)) {

Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
logger.info(
`[FAST_HYDRATE] Reconciling ntfyEndpoints from server (server=${serverEndpoints.length}, store=${currentEndpoints.length})`
);
Expand Down
12 changes: 10 additions & 2 deletions apps/ui/src/store/app-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1506,7 +1506,11 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
set({ eventHooks: hooks });
try {
const httpApi = getHttpApiClient();
await httpApi.settings.updateGlobal({ eventHooks: hooks });
await httpApi.settings.updateGlobal({
eventHooks: hooks,
// Signal the server that an empty array is intentional (not a wipe from stale state)
...(hooks.length === 0 ? { __allowEmptyEventHooks: true } : {}),
});
} catch (error) {
logger.error('Failed to sync event hooks:', error);
}
Expand All @@ -1517,7 +1521,11 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
set({ ntfyEndpoints: endpoints });
try {
const httpApi = getHttpApiClient();
await httpApi.settings.updateGlobal({ ntfyEndpoints: endpoints });
await httpApi.settings.updateGlobal({
ntfyEndpoints: endpoints,
// Signal the server that an empty array is intentional (not a wipe from stale state)
...(endpoints.length === 0 ? { __allowEmptyNtfyEndpoints: true } : {}),
});
} catch (error) {
logger.error('Failed to sync ntfy endpoints:', error);
}
Expand Down
Loading