de431386ea
Messages: - Reply-to: hover action, composer chip with cancel, quote bubble inside the replying message with tap-to-jump + amber highlight ring - Search: header search button toggles in-conversation search bar with prev/next + match counter, auto-jump to active match - Forward: multi-select conversation picker. Attachments are now carried over: download + decrypt source, re-encrypt under each target conv-key, re-upload with fresh per-attachment keys, insert new attachment rows Conversations: - Archive + mute per member. New migration 20260420000001 adds `archived` + `muted_until` on conversation_members. Shared helpers: setConversationArchived / setConversationMutedUntil / isConversationMuted - ChatsPage: archive toggle in header with unread badge for archived bucket, split active/archived lists, muted indicator (BellOff icon, dimmed unread badge) - ConversationRowMenu via createPortal (escapes sidebar overflow clip), forwardRef-based MenuItem so submenu positioning refs survive React 18 - ConversationsContext: suppresses notification sound + OS notif when target conversation is muted - Refresh on `profiles UPDATE` realtime so peer avatar / displayName changes flow to conversation.members without manual refresh Resilience: - ErrorBoundary (Discord-style): centred spinner + escalating copy, no manual reload button. Backoff retry schedule [2s, 4s, 8s, 15s, 30s]. Uses a keyed Fragment (not a div wrapper) so flex h-full chains survive - App wrapped root + per-route RouteBoundary, conversation-level boundary - AuthContext: flip `ready` immediately on cached session read; validate getUser in background so a stalled/offline Supabase doesn't freeze the app on the loading spinner Crypto: - Swap libsodium-wrappers -> libsodium-wrappers-sumo (compact build was missing crypto_pwhash so Argon2id vault KDF threw, falling back to plaintext localStorage on every launch) - Shim d.ts for sumo types (sumo is API superset, no official types ship) - vite optimizeDeps includes sumo with the "require" condition - secureFileStore: exists(dir) check before mkdir; surface genuine permission errors instead of silent catch Tauri: - fs scope adds `$APPLOCALDATA` direct entry (not just /**) so the app data directory itself can be mkdir'd on first launch Chat layout: - Skip call_event messages when computing avatar run boundaries so a regular bubble followed by a call event from the same sender still shows its avatar
39 lines
1.2 KiB
TypeScript
39 lines
1.2 KiB
TypeScript
import react from '@vitejs/plugin-react';
|
|
import path from 'node:path';
|
|
import process from 'node:process';
|
|
import { defineConfig } from 'vite';
|
|
|
|
const host = process.env.TAURI_DEV_HOST;
|
|
|
|
export default defineConfig({
|
|
plugins: [react()],
|
|
resolve: {
|
|
alias: {
|
|
'@': path.resolve(__dirname, './src'),
|
|
'@shared': path.resolve(__dirname, '../../packages/shared/src'),
|
|
'@db-types': path.resolve(__dirname, '../../packages/db-types/src'),
|
|
'@ui-web': path.resolve(__dirname, '../../packages/ui-web/src'),
|
|
},
|
|
},
|
|
optimizeDeps: {
|
|
// libsodium-wrappers-sumo (and the compact variant) ship broken "import"
|
|
// conditions in package exports — the ESM bundle references a sibling
|
|
// ./libsodium.mjs that isn't in the published artefact. Force esbuild to
|
|
// pick the "require" condition so the self-contained CJS build is used.
|
|
include: ['libsodium-wrappers-sumo'],
|
|
esbuildOptions: {
|
|
conditions: ['require', 'node', 'default'],
|
|
},
|
|
},
|
|
clearScreen: false,
|
|
server: {
|
|
port: 1420,
|
|
strictPort: true,
|
|
host: host ?? false,
|
|
...(host ? { hmr: { protocol: 'ws' as const, host, port: 1421 } } : {}),
|
|
watch: {
|
|
ignored: ['**/src-tauri/**'],
|
|
},
|
|
},
|
|
});
|