Commit Graph
26 Commits
Author SHA1 Message Date
Claude bf508c9e6b chore(client): remove abandoned SolidJS beachhead (D6)
The Solid.js migration was abandoned (per CHANGELOG); the 154-LOC
beachhead and its scaffolding remained in-tree, leaving two UI paradigms
for contributors. Removed:

- src/components/solid/ (Badge, ChannelListItem, PluginContainer — none
  imported by production code)
- src/lib/solidMount.ts and src/lib/solidAdapter.ts
- tests/setup-solid.ts and tests/setup-solid.test.tsx
- vite-plugin-solid from vite.config.ts and vitest.config.ts (and the
  now-unneeded tsx test include + setupFiles)
- jsx/jsxImportSource from tsconfig.json
- solid-js, @solidjs/testing-library, vite-plugin-solid from package.json

docs/client-architecture.md (which described the SolidJS design) is
retired to a pointer at docs/architecture/client.md; README links
updated. Audit A-2026-07-12 and decision D6 marked closed.

Verified: tsc --noEmit clean (previous 3 test-file errors were caused by
the Solid jsx config and are gone); oxlint/eslint error counts identical
to HEAD (pre-existing); vitest runner healthy on a sample suite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UA17KPvqGBX3XbXYnMf1rA
2026-07-19 13:57:28 +00:00
J3vbandClaude Fable 5 66cdd2ad9f chore(release): stamp client version 1.1.0-alpha.2
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 10:50:37 +02:00
J3vbandClaude Fable 5 9169dc99a1 chore(release): stamp client version 1.1.0-alpha.1
Forward-only versioning for the alpha reset: 1.1.0-alpha.N ascends
past the superseded v1.0.0 for every installed client, and the alpha
series stays below 1.1.0-beta.N and the final 1.1.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 15:37:01 +02:00
Claude 6608dd392f fix(client): correct prettier endOfLine and oxlint disable directives
The Client Typecheck & Test CI job was failing on the prettier format
check. Two real root causes, fixed properly:

1. prettier endOfLine was set to 'crlf' but the repo stores files with
   LF (no .gitattributes forcing eol), so 'prettier --check' failed on
   292 files on the Linux CI runner. Set endOfLine to 'lf' to match the
   on-disk reality. Also reformat the 2 files (pluginBridge.ts,
   solidAdapter.ts) that had genuine style issues.

2. 15 'eslint-disable-next-line' comments targeted oxlint-only rules
   (no-await-in-loop, no-unassigned-vars) that ESLint does not enable,
   so ESLint reported them as 'Unused eslint-disable directive'
   warnings. Switched the directive prefix to 'oxlint-disable-next-line'
   — oxlint still honors them (its native syntax), and ESLint no longer
   parses them as eslint directives, so the warnings are gone without
   suppressing the safety check or removing the directives that oxlint
   actually relies on.

Verified locally: oxlint, tsc --noEmit, eslint, prettier --check, and
npm audit --audit-level=high all exit 0.
2026-04-07 07:46:49 +00:00
Claude a2cb224323 feat: scaffold Phase B + C (events, telemetry, plugins, Solid.js)
Phase B Step 6 — Solid.js incremental migration
  - vite-plugin-solid + solid-js + @solidjs/testing-library in package.json
  - vite.config.ts compiles src/components/solid/** as Solid TSX
  - tsconfig.json gains jsx: preserve / jsxImportSource: solid-js
  - lib/solidAdapter.ts wraps existing custom Stores as Solid signals
  - lib/solidMount.ts adapts Solid render to {mount,destroy} contract
  - components/solid/Badge.tsx (proof-of-concept leaf)
  - components/solid/ChannelListItem.tsx (store-subscribed leaf)
  - components/solid/Badge.test.tsx pipeline smoke test
  - components/solid/README.md documents the migration recipe

Phase B Step 7 — Event persistence layer
  - SQLite + Postgres migrations for the events table
  - sqlc query files for both engines
  - EventStore interface + SQLite raw-SQL impl + MemStore impl + pg stubs
  - ws.EventPersister: async batched writer (queue / flush / drain / drop)
  - ws.StartEventPruner: background retention pruner
  - hub persists every replay-buffer push and exposes reconnect-tier counters
  - serve.handleReconnect: tiered replay (buffer -> DB -> full re-sync)
  - EventPersistenceConfig + main.go wiring
  - event_persister_test.go covers batching / drops / drain

Phase B Step 8 — OpenTelemetry skeleton
  - Server/telemetry package with public Provider/Tracer/Meter/Counter API
  - telemetry_default.go (no-op build) + telemetry_otel.go (build tag otel)
  - telemetry/metrics.go declares the AppMetrics bundle
  - HTTPMiddleware mounted in Chi router (pass-through in default build)
  - PrometheusHandler optionally mounted at /metrics
  - Spans on MessageService.SendMessage, PermissionService.HasChannelPerm,
    ChannelService.ListVisibleChannels
  - Reconnect-tier counter wired into the global meter
  - TelemetryConfig defaults

Phase C Step 9 — Wazero plugin runtime skeleton
  - Server/plugin package: manifest parser, loader, registry, host APIs
    (commands, storage, events, http, ui), errors
  - sandbox_default.go (no-op) + sandbox_wazero.go (build tag wazero)
  - SQLite + Postgres migrations for plugins + plugin_kv tables
  - PluginStore interface + impls + pg stubs
  - plugin/examples/hello manifest + README
  - plugin_test.go covers manifest, loader, capability gating
  - api/plugins_handler.go admin REST surface, mounted under admin group
  - PluginsConfig + main.go wiring (disabled by default)
  - Client: lib/pluginBridge.ts iframe + postMessage host
  - Client: components/solid/PluginContainer.tsx Solid host component

Verification
  - Default build (no -tags) is intended to compile cleanly with no new
    third-party dependencies. The sandbox lacked Go 1.25.0 so go build
    could not run; PHASE_BC_LOCAL_TODO.md enumerates the local follow-up
    work (npm install, go mod tidy, sqlc-generate, real otel/wazero
    wiring, remaining service spans, full Solid migration).
2026-04-06 09:00:47 +00:00
jevb 5cec992c1f chore: add dev tooling — Stryker, gremlins, k6, toxiproxy, Coraza WAF, Zod
Install and configure mutation testing (Stryker for client, go-gremlins
for server), load testing (k6), chaos testing (toxiproxy), WAF middleware
(Coraza with OWASP rules, opt-in via waf_enabled config), and Zod for
runtime schema validation. All tools verified building cleanly.
2026-04-01 13:49:06 +02:00
jevb 87ba387623 chore: update tooling, CI workflows, and dependencies
Update CI/release workflows, gitignore, package dependencies,
Tauri config, and add linter/formatter configs (oxlint, prettier,
knip, vitest browser config).
2026-04-01 11:40:55 +02:00
J3vb 694007d5a4 Merge pull request #87 from J3vb/dependabot/npm_and_yarn/Client/tauri-client/livekit-client-2.18.0
chore(deps): bump livekit-client from 2.17.3 to 2.18.0 in /Client/tauri-client
2026-03-30 23:49:15 +02:00
dependabot[bot] d5bca972db chore(deps): bump livekit-client in /Client/tauri-client
Bumps [livekit-client](https://github.com/livekit/client-sdk-js) from 2.17.3 to 2.18.0.
- [Release notes](https://github.com/livekit/client-sdk-js/releases)
- [Changelog](https://github.com/livekit/client-sdk-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/livekit/client-sdk-js/compare/v2.17.3...v2.18.0)

---
updated-dependencies:
- dependency-name: livekit-client
  dependency-version: 2.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 21:32:42 +00:00
dependabot[bot] 5045346c1a chore(deps): bump typescript-eslint in /Client/tauri-client
Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.57.2 to 8.58.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.58.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 21:32:33 +00:00
jevb 0e29d98d9d fix: resolve CI failures — eslint peer dep conflict and errcheck lint errors
Downgrade @eslint/js to ^9.39.4 to match eslint ^9 peer requirement.
Fix 7 unchecked .Close() return values flagged by errcheck linter.
2026-03-30 21:54:24 +02:00
jevb 795ed48ec9 docs: v1.0.0 release prep — version bump, license, README overhaul
- Bump version to 1.0.0 across package.json, Cargo.toml, tauri.conf.json
- Add AGPL-3.0 LICENSE file
- Update README with missing features (2FA, DMs, video grid, stream preview,
  theming, auto-login, account deletion, observability)
- Remove internal Copilot Assets section from README
- Remove soundboard reference (not implemented)
- Add account deletion and video grid docs to CLAUDE.md
2026-03-30 20:54:05 +02:00
jevb 5c616d53fe test: fix 10 test quality bugs (BUG-058–067) and resolve 115 TS type errors
BUG-058: Unblock prod-build E2E — created tsconfig.build.json excluding
tests from the production build. Added typecheck/typecheck:build scripts.

BUG-059: Harden native E2E — CDP timeout 30→60s with exponential backoff,
config timeouts doubled (test 120s, action 30s, nav 45s, expect 15s).

BUG-060: Add 25 Rust unit tests across commands.rs, ws_proxy.rs,
livekit_proxy.rs, credentials.rs (was zero behavioral tests).

BUG-061/067: Add behavioral assertions to server coverage_boost_test.go —
GracefulStop verifies client count, channel_focus verifies no error sent.

BUG-062: Upgrade low-signal test assertions in livekit-session,
device-manager, channel-controller (no-op checks → state checks).

BUG-063: Consolidate native E2E skip gates into beforeEach blocks
(voice-controls 7→1 skip, channel-navigation 4→1 skip).

BUG-064: Add 9 integration tests for channel CRUD, member lifecycle,
DM open/close, and presence events.

BUG-065: Replace 3 fixed sleeps with condition-based waits in E2E specs.

BUG-066: Verified toast/audio tests already cleaned in prior session.

TypeScript: Fix 115 type errors across 21 test files — add non-null
assertions for strict indexing, fix mock typing (vi.fn<any>()), add
missing fields (color, version, deleted) to test fixtures.
2026-03-30 16:35:02 +02:00
jevb cdb56f1619 chore: ESLint config, 61 lint fixes across 22 client files, CLAUDE.md update
- Add ESLint v9 flat config with typescript-eslint
- Fix no-floating-promises, no-unused-vars, consistent-return across client
- Refactor livekitSession: delegate entirely to AudioPipeline (1438→1171 lines)
- Add 7 delete-account UI tests in settings-overlay.test.ts
- Update CLAUDE.md with latest features and project structure
- Update .gitignore
2026-03-29 19:40:11 +02:00
jevb e03456527b fix: resolve LiveKit voice issues — duplicate audio, tunnel effect with 5+ users
- Detach existing audio elements before attaching to prevent double playback on reconnects
- Remove webAudioMix to eliminate Web Audio overhead compounding with multiple participants
- Use participant.setVolume() for full 0-200% per-user volume range
- Add pli_throttle and active_loopback_prevention to LiveKit server config
- Bump version to 1.3.0
2026-03-22 21:10:02 +01:00
jevb aa162d88c5 feat: replace client WebRTC with LiveKit SDK (Phase 2)
Client changes:
- Create livekitSession.ts (~400 lines, replaces 1105-line
  voiceSession.ts): Room lifecycle, device switching via
  switchActiveDevice, RNNoise pre-processing for enhanced NS
- types.ts: add VoiceTokenPayload, remove VoiceOffer/Answer/Ice
  payloads, remove ThresholdMode
- dispatcher.ts: replace voice_offer/answer/ice handlers with
  single voice_token handler
- VoiceCallbacks.ts: swap imports to livekitSession
- VoiceAudioTab.ts: remove silence suppression toggle, inline
  threshold math (removed vad.ts dependency)
- Update all files importing from deleted modules

Deleted files (11 source + 5 test):
- webrtc.ts, vad.ts, voiceSession.ts, audio.ts, video.ts,
  Soundboard.ts + their test files

Kept: noise-suppression.ts + @jitsi/rnnoise-wasm (Krisp is
LiveKit Cloud only, not available for self-hosted)

Added: livekit-client@^2.17.3

TypeScript compiles with zero errors (tsc --noEmit).
2026-03-20 05:46:19 +01:00
jevb 7ebf2faecd chore: bump version to 1.2.0 for LiveKit migration 2026-03-20 05:07:37 +01:00
jevb f3734bf827 fix: voice rejoin failure, SDP race, deafen bypass + add server voice logging
- Fix SDP signaling race condition: add per-client negoMu to serialize
  renegotiateParticipant / handleVoiceOffer / handleVoiceAnswer so
  concurrent OnTrack goroutines don't race through rollback
- Fix handleVoiceLeave triple-fire: early return when clearVoice()
  returns zeros so ICE callbacks don't re-enter and corrupt state
- Fix SQLite SQLITE_BUSY errors: add busy_timeout=5000 pragma and
  SetMaxOpenConns(1) for file-based databases
- Fix deafen bypass: new remote audio elements now respect localDeafened
  state so late-arriving streams are muted immediately
- Add debug-level logging for SDP negotiation, track fan-out, ICE
  candidates, voice state changes, room lifecycle, and participant
  add/remove
- Bump version to 1.1.1
2026-03-19 21:35:18 +01:00
jevb c784d7950c chore: bump version to 1.1.0
Video chat, GIF picker, push-to-talk, desktop notifications,
compact mode, and admin IP restriction.
2026-03-19 18:44:29 +01:00
jevb 5311d0a7e3 feat: fix voice chat over NAT, audio pipeline, and add comprehensive debugging
Voice was broken over NAT due to multiple issues across the audio pipeline:

- Fix GainNode silence: WebView2 silences remote WebRTC streams routed through
  Web Audio createMediaStreamSource→GainNode→createMediaStreamDestination.
  Replaced with direct HTMLAudioElement playback for remote audio.
- Fix NAT traversal: Add Google public STUN server (stun.l.google.com:19302)
  so remote clients can discover their public IP for ICE connectivity.
- Fix signaling race: Catch createOffer InvalidStateError when server
  renegotiation offer arrives before client's initial offer is sent.
- Fix device switch: Use replaceTrack() instead of removeTrack+addTrack
  to avoid SDP renegotiation. Safe rollback on failure (stop old last).
- Fix speaking flicker: setSpeakers skips local user (VAD is sole authority).
- Fix VAD sample rate: Force 48kHz AudioContext instead of system default
  (192kHz) which spread FFT bins too wide for voice frequency detection.
- Fix CSP for WASM: Add wasm-unsafe-eval to script-src for RNNoise.
- Fix clearAuth leak: leaveVoice() called before resetVoiceStore().
- Fix ICE rate limit: Separate limit for ICE candidates (50/s vs 20/s).
- Fix stale ICE errors: Silently drop voice_ice with no PeerConnection.
- Fix audio play() race: Deferred to queueMicrotask after DOM attachment.

Debugging infrastructure:
- Logs tab: Copy All button, Voice Diagnostics panel with live session
  state, Probe Audio Levels (measures actual signal at 3 pipeline points),
  Test Direct Playback button, Copy Diagnostics button.
- Client logging: WebRTC (PeerConnection lifecycle, ICE candidates with
  type/address, track events, negotiation), VAD (start/threshold/destroy),
  Audio (device acquisition with settings, device changes), noise suppression
  (WASM load timing, worklet vs fallback path), voiceSession (remote stream
  parsing failures, deafen state, audio element playback events).
- Server logging: SFU init config, voice room mode transitions/track
  lifecycle/close, RTP forwarding with packet counts and first-packet
  detection, 5s no-packet warning, track fan-out counts, subscriber
  transceiver state, ICE candidate details, voice credentials issued.
- Logger: Error objects now serialize .message and .stack instead of {}.

Per-user volume right-click now works on voice user rows in sidebar.
RNNoise ML noise suppression with AudioWorklet + ScriptProcessor fallback.
Tests: 7 new test cases (replaceTrack, setSpeakers skip-local, clearAuth).
2026-03-18 23:02:06 +01:00
jevb 01e4d4bec3 feat: client auto-update with Ed25519 signing and dynamic server URL
- Add tauri-plugin-updater and tauri-plugin-process for in-app updates
- Rust commands (check_client_update, download_and_install_update) build
  updater with dynamic endpoint at runtime for self-hosted compatibility
- Server endpoint GET /api/v1/client-update/{target}/{version} translates
  GitHub Releases into Tauri updater JSON format with .sig content
- UpdateNotifier banner component with install/dismiss controls
- CI workflow produces signed .nsis.zip + .sig updater artifacts
- Self-signed TLS support via dangerousAcceptInvalidCerts config
2026-03-18 17:47:59 +01:00
jevb 750a7af052 feat: native file downloads, upload size fix, native E2E tests
- Add file download with native save dialog (Tauri dialog + fs plugins)
- Make attachment filename clickable as additional download trigger
- Add download button with hover styling to file attachments
- Exempt /api/v1/uploads from global 1MB body size limit (MaxBodySizeUnless)
- Add native E2E test suite (8 specs) with Playwright CDP fixture
2026-03-18 17:10:16 +01:00
jevb 13be0fd6d3 feat: file uploads, URL previews, emoji search, voice mute fixes, UX improvements
Server:
- Add POST /api/v1/uploads and GET /api/v1/files/{id} endpoints
- Add CreateAttachment DB method for file upload records
- Allow empty message content when attachments are present
- CORS headers on file serving for WebView2 compatibility

Client — File uploads & attachments:
- Clipboard paste (Ctrl+V) and attach button (+) for file uploads
- Preview bar above input with thumbnail, spinner, and remove button
- Images fetched via Tauri HTTP plugin as base64 data URIs (bypasses
  self-signed cert rejection in WebView2)
- Three-layer image cache: memory → IndexedDB → network
- In-flight deduplication prevents duplicate concurrent fetches
- Image lightbox with click-to-zoom, scroll wheel zoom, pan, keyboard shortcuts

Client — URL previews & embeds:
- URLs in messages rendered as clickable links
- YouTube embeds with thumbnail, play button, video title via oEmbed API
- Generic link previews with OG metadata (title, description, image)
- Fetched via Tauri HTTP plugin with Facebook crawler User-Agent
- YouTube title cache and OG metadata cache prevent re-fetch on re-render
- Links open in default browser via tauri-plugin-opener

Client — Voice & audio fixes:
- Mute uses replaceTrack(null) for reliable RTP-level muting in WebView2
- Deafen also mutes mic; undeafen/unmute unmutes both
- Muted users show crossed mic icon, deafened show crossed mic + headphone
- Re-apply mute state after input device switch

Client — UX improvements:
- Disable browser context menu globally (only custom menus show)
- Emoji search now matches by keyword names (smile, heart, fire, etc.)
- Emoji picker closes on click outside
- User bar status text moved below username
- Messages sorted chronologically (oldest first, newest at bottom)
- Scroll to bottom on initial load with deferred retries for layout shifts
- Image attachments constrained to 400x350px with click-to-lightbox
2026-03-18 14:13:52 +01:00
jevb 8f4349ba42 feat: server enhancements, client test selectors, and UI polish
Server:
- Add message search and pinned messages support
- Add admin hub integration and live connection stats
- Update admin test mocks for hub interface

Client:
- Add data-testid attributes to components for E2E testing
- Add window management capabilities (position, size, maximize)
- Add prod E2E test config and script
- Fix CSS imports (use vite bundling instead of HTML link tags)
- Add inline styles to InviteManager overlay for reliability
- Update CHATSERVER.md references from WPF to Tauri

Docs:
- Update quick-start guide
2026-03-17 02:56:19 +01:00
jevb 01387dc033 feat: fix all E2E failures, add credentials/window-state, wire QuickSwitcher + SettingsOverlay
- Fix 80 E2E test failures across 6 root causes (channel auto-select,
  settings overlay wiring, QuickSwitcher Ctrl+K, voice widget visibility,
  member list rendering, status dot positioning)
- Add Tauri credential storage (Rust + TS bridge) and window-state persistence
- Add ConnectedOverlay component and settings-overlay/window-state unit tests
- Expand profiles and rate-limiter with comprehensive test coverage
- Add CODE_REVIEW.md documenting 4 Critical + 3 High server-side issues
- Add Playwright E2E suite (135 tests across 14 spec files)
- All 586 tests passing (451 unit/integration + 135 E2E)
2026-03-16 16:43:46 +01:00
jevb 77626e136b feat: add Tauri v2 desktop client with full chat UI and security hardening
Complete Tauri v2 client implementation migrated from WPF/.NET 8:
- Rust backend: WS proxy with TLS cert bypass for self-signed servers,
  settings storage, system tray, global hotkeys
- TypeScript frontend: login/register, chat messaging, channel sidebar,
  member list, voice channel UI, settings overlay with log viewer,
  server profiles, quick switcher, emoji picker, file uploads
- 21 test suites (364 tests) covering stores, services, and components
- Security: bounded WS channel, wss:// URL validation, TLS signature
  verification, profile import validation, token redaction, HTTPS-only
  HTTP scope

Also updates CLAUDE.md to correct API path rule (/api/v1/) and adds
Tauri client CI workflow.
2026-03-15 19:44:02 +01:00