- Lazy-import CreateRoomForm/CreateSpaceForm in CreateRoom.tsx and Create.tsx
so create-room and create-space get their own chunks; eliminates
INEFFECTIVE_DYNAMIC_IMPORT warnings
- Add RouteError component wired to root route errorElement so crashes show
a reload button instead of React Router dev screen
- ci.yml: use secrets.SENTRY_AUTH_TOKEN so source maps upload on CI builds
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix timelineSegments useMemo stale cache: the Perf-5 optimization used
timeline.linkedTimelines as its only dep, but that reference never changes
when events are added in-place; adding eventsLength as a dep makes it
recompute on every new live event so the binary search always finds the
new item
- Add LobbySkeleton: shimmer placeholder for space lobby (header + hero +
room list rows) shown while the Lobby chunk lazy-loads
- Add AuthSkeleton: shimmer placeholder for auth pages (logo + server
picker + form fields) shown while AuthLayout chunk lazy-loads
- Wire both into Router.tsx fallback props
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Automated cleanup removed const mx = useMatrixClient() from 3 more components
that use it (MessagePinItem, Message, Event) in addition to the 2 fixed in
the previous hotfix. Root cause: the cleanup script used substring matching
on indentation which removed declarations at any indent level, not just the
one targeted unused variable.
All 5 components that call mx.* now have their declarations restored.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The automated unused-var cleanup incorrectly removed const mx = useMatrixClient()
from MessageDeleteItem and ReportMessage components in Message.tsx. Both components
use mx inside their useCallback closures (mx.redactEvent, mx.reportEvent). This
caused a ReferenceError crash on the messages view in production.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Synapse does not yet ship MSC3786/MSC3914 as server-default push rules.
matrix-js-sdk patches them client-side every login and warns. Filter these
at console.warn level -- functionality is unaffected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ServerConfigsLoader: skip validateAuthMetadata when getAuthMetadata()
rejects (404 on /auth_issuer means server uses traditional SSO, not
native Matrix OIDC/MAS - this is expected and should not log errors)
- Router: use HydrateFallback={() => null} instead of hydrateFallbackElement={null}
so react-router v7 counts it as truthy and suppresses the spurious warning
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- react 18.2.0 to 19.2.6
- react-dom 18.2.0 to 19.2.6
- @types/react 18.2.39 to 19.2.15
- @types/react-dom 18.2.17 to 19.2.3
React 19 breaking changes fixed:
- useRef<T>(null) now returns RefObject<T | null>; cast to
RefObject<T> at 16 component call sites (safe, runtime unchanged)
- useRef<T>() without arg no longer valid; add | undefined>(undefined)
in useDebounce, useFileDrop, useThrottle, useVirtualPaginator hooks,
RoomInput, RoomTimeline, and ClientNonUIFeatures
- useReducer<typeof reducer> 1-arg form removed; drop explicit type arg
in useForceUpdate (inferred from reducer function)
- global JSX namespace removed; import type { JSX } from react in
react-custom-html-parser.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- typescript 5.9.3 to 6.0.3
- moduleResolution Node to bundler (correct for Vite projects)
- target/lib ES2016 to ES2020 (enables flatMap, Promise.allSettled)
- Fix global to globalThis in initMatrix.ts (browser env)
- Fix EventEmitter default to named import in CallControl.ts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolves all TS2345/TS2347/TS7006 type errors introduced by stricter TypeScript 5.x.
Fix Icons.Settings to Icons.Setting, cast account data returns, fix implicit any.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a new deploy lands while a tab is open, lazy-loaded chunks (like
GifPicker) disappear because their content-hash filename changes. Vite
dispatches a vite:preloadError event in this case. We reload once and
clear the flag on successful load so future deploys can trigger again.
Icons.Settings is undefined in folds v2.6.2; only Icons.Setting exists.
This caused TypeError: i is not a function when rendering m.room.join_rules
or m.room.guest_access state events in the room timeline, crashing DMs with
those events visible in the initial view.
react-router v7's generatePath() now calls encodeURIComponent() on all
path params. pathUtils.ts was also calling encodeURIComponent() before
passing to generatePath, resulting in double-encoding (e.g. '#' became
'%2523' instead of '%23').
This caused spaces/rooms with alias paths to receive double-encoded
room IDs from useParams(), which were then re-encoded by matrix-sdk
when making HTTP requests (400 Bad Request from Synapse).
Remove the manual encodeURIComponent() calls -- generatePath handles it.
- Fix prettier formatting in useCall.ts and initMatrix.ts (unblocks CI)
- Fix viteStaticCopy stripBase so manifest.json and public/locales/ land
at correct output paths (was getting extra 'public/' prefix from v4 path
preservation behavior)
- Silence react-router v7 HydrateFallback warning on root route (SPA has
no SSR hydration, null is intentional)
When matrix-sdk is briefly upgraded then reverted, the local IndexedDB
schema version is higher than the SDK expects. Detect the VersionError
DOMException and show a clear 'Clear local data and reload' button
instead of a cryptic error message.
@giphy/react-components@10.x calls styled-components internals
(mergeAttributes) that do not exist in styled-components v6 — crashes
on open. Reverted to 1.6.0 until giphy publishes a v6-compatible release.
WelcomePage: remove Sentry test button (verified working), rename
Support -> Lotus Matrix Guide.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prettier: auto-formatted 103 files to fix baseline. Prettier check in CI
is now a hard gate (removed continue-on-error).
Brotli: installed libnginx-mod-http-brotli-filter/static. Enabled in nginx
with brotli_static on for pre-compressed assets and comp_level 6.
Sentry releases: deploy script now exports VITE_APP_VERSION=<git-short-sha>
before building so each Sentry release maps to an exact commit.
CI also passes github.sha as VITE_APP_VERSION.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
RoomSkeleton: shimmer skeleton matching Room header/timeline/input layout,
used as Suspense fallback for all three Room routes (home/direct/space)
Sentry source maps: @sentry/vite-plugin uploads 72 hidden source map files
to Sentry on each build then deletes them from dist — stack traces now show
real file/line numbers instead of minified bundle positions.
Auth token loaded from /etc/lotus-deploy.env (not in git).
Auto-deploy: webhook receiver on port 9001, nginx proxies
/hooks/lotus-deploy, HMAC-SHA256 verified, triggers on lotus branch push.
Deploy script: git reset --hard + npm ci + npm run build + rsync to webroot.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
browserTracingIntegration injects sentry-trace and baggage headers into all
outgoing fetch calls. Synapse does not list these in Access-Control-Allow-Headers,
so every Matrix API call was blocked by the browser CORS preflight check.
Removed browserTracingIntegration, set tracePropagationTargets:[] and
tracesSampleRate:0. Error capture (the useful part) is unaffected.
CSP fix (Sentry ingest domain) is applied via nginx — no code change needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Initialize Sentry SDK in index.tsx when VITE_SENTRY_DSN env var is set
- Wrap entire App with Sentry.ErrorBoundary (replaces the hard crash with a retry UI)
- 5% trace sample rate, sendDefaultPii disabled, strip events containing accessToken
- Add .env.production template with VITE_SENTRY_DSN placeholder
- Get your DSN from sentry.io -> Project Settings -> Client Keys
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lobby, Explore/FeaturedRooms/PublicRooms, Inbox/Notifications/Invites are
now lazy-loaded via React.lazy so they only enter the bundle when navigated
to. Main bundle: 2547 kB → 2472 kB (gzip 637 → 618 kB).
Spoiler aria-pressed was initialised to false (revealed); changed to true
so the spoiler starts hidden, matching CSS logic (aria-pressed=true →
color:transparent).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously every visible Message subscribed to settingsAtom via useSetting,
creating O(80) active atom subscriptions. Now RoomTimeline reads it once
and passes it down as a prop, reducing subscriptions to 1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
C-1 complete sweep across all components and features:
- Call controls: mic mute/unmute, deafen/undeafen, video, screenshare, chat
- RoomInput: dismiss reply, attach file, sticker, emoji, GIF, location, toolbar
- Media viewers: close in image/pdf/text viewers and editors
- Settings dialogs: close buttons in all room/space/common settings panels
- Lobby: back, toggle member list, scroll to top, pack add/remove
- Auth: server picker, UIA flow cancel
- Upload cards: cancel uploads
- URL preview: prev/next buttons
- Members drawer: close + scroll to top
- RoomViewHeader: back, start call, toggle member list
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Perf-3: Replace raw roomToUnreadAtom subscription in Home, Direct, Space with
selectAtom-derived Set<string> — components now only re-render when rooms
gain/lose unread presence, not on every notification count update
Perf-5: RoomTimeline eventRenderer now uses binary search on precomputed
timelineSegments instead of O(N×T) linear scan per visible message
A11y L-1: Add as=h2 semantic heading to Home, Direct, Inbox, Space page nav
titles so screen readers announce page sections correctly
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BUG-18: clearTimeout cleanup in focusItem useLayoutEffect prevents leaked timers
BUG-24: Room timeline listener catches first poll vote before Relations object exists
BUG-25: Use timelineRef.current in handleOpenEvent to prevent stale index on rapid navigation
Perf-6: React.lazy + Suspense for GifPicker and EmojiBoard (initial bundle -114 kB)
Perf-7: React.memo on RoomNavItem to prevent re-renders on unrelated state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>