Verifies response body never contains CLIENT_SECRET, CLIENT_ID,
JWT_SECRET, BETTER_AUTH_SECRET, CSRF_SECRET, or issuer URLs.
Refs #413
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add getAuthConfig() to AuthService (email always, OIDC when enabled)
- Add GET /auth/config public endpoint with Cache-Control: 5min
- Place endpoint before catch-all to avoid interception
Refs #413
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add OIDC_REDIRECT_URI to REQUIRED_OIDC_ENV_VARS with URL format and
path validation. The redirect URI must be a parseable URL with a path
starting with /auth/callback. Localhost usage in production triggers
a warning but does not block startup.
This prevents 500 errors when BetterAuth attempts to construct the
authorization URL without a configured redirect URI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comprehensive plan for fixing the production 500 on POST /auth/sign-in/oauth2
and redesigning the frontend login page to be OIDC-aware with multi-method
authentication support.
Key areas covered:
- Backend: OIDC startup validation, auth config discovery endpoint, BetterAuth
error handling, PKCE, session hardening, trustedOrigins extraction
- Frontend: Multi-method login page, PDA-friendly error display, adaptive UI
based on backend-advertised providers, loading states, accessibility
- Security: CSRF rationale, secret leakage prevention, redirect URI validation,
session idle timeout, OIDC health checks
- 6 implementation phases with file change map and testing strategy
Created with input from frontend design, backend, security, and auth architecture
specialist reviews.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The genericOAuth plugin is conditionally loaded based on OIDC_ENABLED
env var. Without it, BetterAuth has no /sign-in/oauth2 route, causing
404 when the login button is clicked.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The global CsrfGuard blocks POST /auth/sign-in/oauth2 with 403 because
unauthenticated users have no session and therefore no CSRF token.
BetterAuth handles its own CSRF protection via toNodeHandler().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Docker/load-balancer health probes hit GET /health every ~5s from
127.0.0.1, exhausting the rate limit and causing all subsequent checks
to return 429 — making the service appear unhealthy.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BetterAuth defaulted basePath to /api/auth but NestJS controller routes
to /auth/* (no global prefix). The auth client also pointed at the web
frontend origin instead of the API server, and LoginButton used a
nonexistent GET /auth/signin/authentik endpoint.
- Set basePath: "/auth" in BetterAuth server config
- Point auth client baseURL to API_BASE_URL with matching basePath
- Add genericOAuthClient plugin to auth client
- Use signIn.oauth2({ providerId: "authentik" }) in LoginButton
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The constant-time comparison test used Date.now() deltas with a 10ms
threshold which is unreliable in CI. Replace with deterministic tests
that verify both same-length and different-length key rejection paths
work correctly. The actual timing-safe behavior is guaranteed by
Node's crypto.timingSafeEqual which the guard uses.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BetterAuth expects Web API Request objects (Fetch API standard) with
headers.get(), but NestJS/Express passes IncomingMessage objects with
headers[] property access. Use better-auth/node's toNodeHandler to
properly convert between Express req/res and BetterAuth's Web API handler.
Also fixes vitest SWC config to read the correct tsconfig for NestJS
decorator metadata emission, which was causing DI injection failures
in tests.
Fixes#410
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Alpine (musl libc) is incompatible with matrix-sdk-crypto-nodejs native binary
which requires glibc's ld-linux-x86-64.so.2. Switched all Node.js Dockerfiles
to node:24-slim (Debian/glibc). Also fixed docker-compose.matrix.yml network
naming from undefined mosaic-network to mosaic-internal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pnpm 10 blocks build scripts by default. The matrix-bot-sdk requires
@matrix-org/matrix-sdk-crypto-nodejs which downloads a platform-specific
native binary via postinstall. Added to onlyBuiltDependencies so the
Alpine (musl) binary gets installed in Docker builds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The 0.1.0 package was ESM-only, causing ERR_PACKAGE_PATH_NOT_EXPORTED
when loaded by NestJS (which compiles to CommonJS). Version 0.1.1 ships
dual ESM/CJS builds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause: migration 20260129235248_add_link_storage_fields dropped the
personalities table and FormalityLevel enum, but migration
20260208000000_add_missing_tables later references personalities in a FK
constraint, causing ERROR: relation "personalities" does not exist on any
fresh database deployment.
Fix 1 — 20260208000000_add_missing_tables:
Recreate FormalityLevel enum and personalities table (with current schema
structure) at the top of the migration, before the FK constraint.
Fix 2 — New migration 20260215100000_fix_schema_drift:
- Create missing instances table (Federation module, never migrated)
- Recreate knowledge_links unique index (dropped, never recreated)
- Add 7 missing @@unique([id, workspaceId]) composite indexes
- Add missing agent_tasks.agent_type index
Verified: all 27 migrations apply cleanly on a fresh PostgreSQL 17 database
with pgvector.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
matrix-bot-sdk depends on the deprecated `request` library which pulls
in vulnerable form-data (<2.5.4, critical: unsafe random boundary) and
qs (<6.14.1, high: DoS via memory exhaustion). Add pnpm overrides to
force patched versions since matrix-bot-sdk has no newer release.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keep both Mosaic Telemetry section (from develop) and Matrix Dev
Environment section (from feature branch) in .env.example.
Regenerate pnpm-lock.yaml with both dependency trees merged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Docker build failed because pip couldn't find mosaicstack-telemetry
from the private Gitea PyPI registry. Copy pip.conf into the image so
pip resolves the extra-index-url during docker build.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical fixes:
- Fix FormData field name mismatch (audio -> file) to match backend FileInterceptor
- Add /speech namespace to WebSocket connection URL
- Pass auth token in WebSocket handshake options
- Wrap audio.play() in try-catch for NotAllowedError and DOMException handling
- Replace bare catch block with named error parameter and descriptive message
- Add connect_error and disconnect event handlers to WebSocket
- Update JSDoc to accurately describe batch transcription (not real-time partial)
Important fixes:
- Emit transcription-error before disconnect in gateway auth failures
- Capture MediaRecorder error details and clean up media tracks on error
- Change TtsDefaultConfig.format type from string to AudioFormat
- Define canonical SPEECH_TIERS and AUDIO_FORMATS arrays as single source of truth
- Fix voice count from 54 to 53 in provider, AGENTS.md, and docs
- Fix inaccurate comments (Piper formats, tier prop, SpeachesProvider, TextValidationPipe)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comprehensive documentation for the speech services module:
- docs/SPEECH.md: Architecture, API reference, WebSocket protocol,
environment variables, provider configuration, Docker setup,
GPU VRAM budget, and frontend integration examples
- apps/api/src/speech/AGENTS.md: Module structure, provider pattern,
how to add new providers, gotchas, and test patterns
- README.md: Speech capabilities section with quick start
Fixes#406
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements the SpeechSettings component with four sections:
- STT settings (enable/disable, language preference)
- TTS settings (enable/disable, voice selector, tier preference, auto-play, speed control)
- Voice preview with test button
- Provider status with health indicators
Also adds Slider UI component and getHealthStatus API client function.
30 unit tests covering all sections, toggles, voice loading, and PDA-friendly design.
Fixes#404
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements AudioPlayer inline component with play/pause, progress bar,
speed control (0.5x-2x), download, and duration display. Adds
TextToSpeechButton "Read aloud" component that synthesizes text via
the speech API and integrates AudioPlayer for playback. Includes
useTextToSpeech hook with API integration, audio caching, and
playback state management. All 32 tests passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix sendThreadMessage room mismatch: use channelId from options instead of hardcoded controlRoomId
- Add .catch() to fire-and-forget handleRoomMessage to prevent silent error swallowing
- Wrap dispatchJob in try-catch for user-visible error reporting in handleFixCommand
- Add MATRIX_BOT_USER_ID validation in connect() to prevent infinite message loops
- Fix streamResponse error masking: wrap finally/catch side-effects in try-catch
- Replace unsafe type assertion with public getClient() in MatrixRoomService
- Add orphaned room warning in provisionRoom on DB failure
- Add provider identity to Herald error logs
- Add channelId to ThreadMessageOptions interface and all callers
- Add missing env var warnings in BridgeModule factory
- Fix JSON injection in setup-bot.sh: use jq for safe JSON construction
Fixes#377
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add SpeechGateway with Socket.IO namespace /speech for real-time
streaming transcription. Supports start-transcription, audio-chunk,
and stop-transcription events with session management, authentication,
and buffer size rate limiting. Includes 29 unit tests covering
authentication, session lifecycle, error handling, cleanup, and
client isolation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add SpeechController with POST /api/speech/transcribe for audio
transcription and GET /api/speech/health for provider status.
Uses AudioValidationPipe for file upload validation and returns
results in standard { data: T } envelope.
Includes 10 unit tests covering transcribe with options, error
propagation, and all health status combinations.
Fixes#392
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add fallback-tier TTS provider using Piper via OpenedAI Speech for
ultra-lightweight CPU-only synthesis. Maps 6 standard OpenAI voice
names (alloy, echo, fable, onyx, nova, shimmer) to Piper voices.
Update factory to use the new PiperTtsProvider class, replacing the
inline stub. Includes 37 unit tests covering provider identity,
voice mapping, and voice listing.
Fixes#395
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Quick start guide for dev environment
- Architecture overview with service responsibilities
- Command reference with examples
- Configuration reference
- Streaming response architecture
- Deployment considerations
Refs #386
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create AudioValidationPipe for MIME type and file size validation,
TextValidationPipe for TTS text input validation, and DTOs for
transcribe/synthesize endpoints. Includes 36 unit tests.
Fixes#398
MB-007 (Streaming AI responses) done in commit 93cd314.
20 new tests, 132 total bridge tests pass.
Launching MB-008 (E2E tests) and MB-009 (Docs) in parallel.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ChatterboxSynthesizeOptions interface with referenceAudio and
emotionExaggeration fields, and comprehensive unit tests (26 tests)
covering voice cloning, emotion control, clamping, graceful degradation,
and cross-language support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MB-005 (Matrix command handling) and MB-006 (Herald adapter) done.
Both committed in ad24720 (bundled by pre-commit hooks).
49 Matrix tests pass, 112 total bridge tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract KokoroTtsProvider from factory into its own module with:
- Full voice catalog of 54 built-in voices across 8 languages
- Voice metadata parsing from ID prefix (language, gender, accent)
- Exported constants for supported formats and speed range
- Comprehensive unit tests (48 tests)
- Fix lint/type errors in chatterbox provider (Prettier + unsafe cast)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>