fix(settings): resync push-rule toggle from account-data; MSC1929 support host

- PushRuleEditor: the enable Switch initialized its state from pushRule.enabled
  once (useState initializer), so a rule toggled on another device left the
  Switch stale until remount. A useEffect now resyncs on pushRule.enabled
  change. pushRule flows from useAccountData(m.push_rules), which re-renders on
  sync, so the resync is genuinely reached; no optimistic-update conflict (the
  toggle sets state only after the PUT resolves).

- About: the "Homeserver Support" panel fetched /.well-known/matrix/support from
  the client-API URL (mx.getHomeserverUrl()). Per MSC1929 that file lives at the
  MXID server-name host (like /.well-known/matrix/client), which differs on
  delegated/split-domain servers. Now fetched from https://{mx.getDomain()};
  identical target for non-delegated servers (incl. Lotus), spec-correct for
  delegated ones, and degrades gracefully (catch → panel hidden) otherwise.

Bug-hunt findings from LOTUS_TODO. Two review agents; both confirmed effective
and non-regressing (full account-data re-render chain traced; CORS/host edge
weighed). Gate-green (tsc, eslint, prettier, 914 tests, build).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 17:00:36 -04:00
co-authored by Claude Opus 4.8
parent b0a3c81b15
commit 2c0cd0d26c
2 changed files with 24 additions and 3 deletions
+9 -2
View File
@@ -42,9 +42,16 @@ function useServerSupport(): { support: MSC1929Support | null; loading: boolean
useEffect(() => {
const controller = new AbortController();
const baseUrl = mx.getHomeserverUrl();
// MSC1929 support info is served from the MXID server-name host (like
// /.well-known/matrix/client), which on delegated/split-domain servers is
// NOT the client-API URL. Derive it from the user's domain.
const serverName = mx.getDomain();
if (!serverName) {
setLoading(false);
return undefined;
}
setLoading(true);
fetch(`${baseUrl}/.well-known/matrix/support`, { signal: controller.signal })
fetch(`https://${serverName}/.well-known/matrix/support`, { signal: controller.signal })
.then((res) => {
if (!res.ok) return null;
return res.json();
@@ -1,4 +1,11 @@
import React, { ChangeEventHandler, FormEventHandler, useCallback, useMemo, useState } from 'react';
import React, {
ChangeEventHandler,
FormEventHandler,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { IPushRule, IPushRules, PushRuleKind } from 'matrix-js-sdk';
import { Box, Text, Button, Input, config, IconButton, Icons, Icon, Spinner, Switch } from 'folds';
import { SettingsSelect } from '../../../components/settings-select/SettingsSelect';
@@ -56,6 +63,13 @@ function RuleEnableToggle({ kind, pushRule }: RuleEnableToggleProps) {
const mx = useMatrixClient();
const [enabled, setEnabled] = useState(pushRule.enabled !== false);
// Re-sync when the rule changes externally (e.g. toggled on another device →
// account-data sync). The useState initializer only runs once, so without
// this the Switch would show a stale value.
useEffect(() => {
setEnabled(pushRule.enabled !== false);
}, [pushRule.enabled]);
const [toggleState, toggle] = useAsyncCallback(
useCallback(
async (value: boolean) => {