react-os-shell 0.7.5 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/apps/Email.tsx"],"names":[],"mappings":"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","file":"Email-ZUDCRZKB.js","sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport useMailAuth from '../hooks/useMailAuth';\nimport { setEmailUnreadCount } from '../hooks/useEmailUnread';\nimport { getMailClient } from '../api/mailClient';\nimport toast from '../shell/toast';\nimport Modal, { ModalActions } from '../shell/Modal';\nimport { formatDate, formatDateTime } from '../utils/date';\n\ninterface Folder {\n path: string;\n name: string;\n delimiter: string;\n specialUse: 'inbox' | 'sent' | 'drafts' | 'trash' | 'junk' | 'archive' | 'flagged' | null;\n subscribed: boolean;\n unreadCount: number;\n totalCount: number;\n}\n\ninterface Address { name: string; address: string }\n\ninterface MessageListItem {\n uid: number;\n threadId: string;\n from: Address;\n to: Address[];\n subject: string;\n snippet: string;\n date: string;\n flags: string[];\n hasAttachments: boolean;\n inReplyTo: string | null;\n references: string[];\n}\n\ninterface AttachmentInfo {\n partId: string;\n filename: string;\n contentType: string;\n size: number;\n contentId: string | null;\n}\n\ninterface MessageDetail extends Omit<MessageListItem, 'snippet' | 'hasAttachments'> {\n cc: Address[];\n text: string | null;\n html: string | null;\n attachments: AttachmentInfo[];\n}\n\nconst SMART_VIEWS: Array<{ key: string; label: string; icon: string }> = [\n { key: '__inbox__', label: 'Inbox', icon: '📥' },\n { key: '__starred__', label: 'Starred', icon: '⭐' },\n { key: '__unread__', label: 'Unread', icon: '●' },\n { key: '__drafts__', label: 'Drafts', icon: '📝' },\n { key: '__sent__', label: 'Sent', icon: '📤' },\n { key: '__trash__', label: 'Trash', icon: '🗑' },\n { key: '__junk__', label: 'Spam', icon: '⚠' },\n];\n\nfunction resolveSmartView(key: string, folders: Folder[]): string {\n if (key === '__inbox__') return folders.find(f => f.specialUse === 'inbox')?.path || 'INBOX';\n if (key === '__sent__') return folders.find(f => f.specialUse === 'sent')?.path || 'Sent';\n if (key === '__drafts__') return folders.find(f => f.specialUse === 'drafts')?.path || 'Drafts';\n if (key === '__trash__') return folders.find(f => f.specialUse === 'trash')?.path || 'Trash';\n if (key === '__junk__') return folders.find(f => f.specialUse === 'junk')?.path || 'Junk';\n return key; // __starred__, __unread__ → handled server-side\n}\n\nexport default function Email() {\n const { isConnected, serverReachable } = useMailAuth();\n\n const [folders, setFolders] = useState<Folder[]>([]);\n const [selectedKey, setSelectedKey] = useState<string>('__inbox__');\n const [messages, setMessages] = useState<MessageListItem[]>([]);\n const [selectedUid, setSelectedUid] = useState<number | null>(null);\n const [detail, setDetail] = useState<MessageDetail | null>(null);\n const [loadingFolders, setLoadingFolders] = useState(false);\n const [loadingList, setLoadingList] = useState(false);\n const [loadingDetail, setLoadingDetail] = useState(false);\n const [composeOpen, setComposeOpen] = useState(false);\n const [composeDraft, setComposeDraft] = useState<DraftState | null>(null);\n const [serverError, setServerError] = useState<string | null>(null);\n\n const selectedFolderPath = useMemo(() => resolveSmartView(selectedKey, folders), [selectedKey, folders]);\n\n const refreshFolders = useCallback(async () => {\n if (!isConnected) return;\n setLoadingFolders(true);\n setServerError(null);\n try {\n const res = await getMailClient().get<{ folders: Folder[] }>('/api/mail/folders');\n setFolders(res.data.folders);\n } catch (err) {\n setServerError(extractError(err));\n } finally {\n setLoadingFolders(false);\n }\n }, [isConnected]);\n\n const refreshList = useCallback(async () => {\n if (!isConnected) return;\n setLoadingList(true);\n setServerError(null);\n try {\n const res = await getMailClient().get<{ messages: MessageListItem[] }>('/api/mail/messages', {\n params: { folder: selectedFolderPath, page: 0, pageSize: 50 },\n });\n setMessages(res.data.messages);\n } catch (err) {\n setServerError(extractError(err));\n } finally {\n setLoadingList(false);\n }\n }, [isConnected, selectedFolderPath]);\n\n useEffect(() => {\n refreshFolders();\n }, [refreshFolders]);\n\n useEffect(() => {\n refreshList();\n setDetail(null);\n setSelectedUid(null);\n }, [refreshList]);\n\n // Poll unread counts every 30s and push to the badge.\n const unreadPollRef = useRef<number | null>(null);\n useEffect(() => {\n if (!isConnected) return;\n async function tick() {\n try {\n const res = await getMailClient().get<{ counts: Record<string, number> }>('/api/mail/unread-counts');\n const inboxFolder = folders.find(f => f.specialUse === 'inbox')?.path || 'INBOX';\n setEmailUnreadCount(res.data.counts[inboxFolder] || 0);\n setFolders(prev =>\n prev.map(f => ({ ...f, unreadCount: res.data.counts[f.path] ?? f.unreadCount }))\n );\n } catch {\n /* ignore polling errors */\n }\n }\n tick();\n unreadPollRef.current = window.setInterval(tick, 30_000) as unknown as number;\n return () => {\n if (unreadPollRef.current) window.clearInterval(unreadPollRef.current);\n };\n }, [isConnected, folders]);\n\n const openMessage = useCallback(async (item: MessageListItem) => {\n setSelectedUid(item.uid);\n setLoadingDetail(true);\n try {\n const res = await getMailClient().get<MessageDetail>(\n `/api/mail/messages/${encodeURIComponent(selectedFolderPath)}/${item.uid}`\n );\n setDetail(res.data);\n if (!item.flags.includes('\\\\Seen')) {\n await getMailClient().post(\n `/api/mail/messages/${encodeURIComponent(selectedFolderPath)}/${item.uid}/flags`,\n { add: ['\\\\Seen'] }\n );\n setMessages(prev =>\n prev.map(m => (m.uid === item.uid ? { ...m, flags: [...m.flags, '\\\\Seen'] } : m))\n );\n }\n } catch (err) {\n toast.error(extractError(err));\n } finally {\n setLoadingDetail(false);\n }\n }, [selectedFolderPath]);\n\n const toggleStar = useCallback(async (item: MessageListItem) => {\n const isFlagged = item.flags.includes('\\\\Flagged');\n try {\n await getMailClient().post(\n `/api/mail/messages/${encodeURIComponent(selectedFolderPath)}/${item.uid}/flags`,\n isFlagged ? { remove: ['\\\\Flagged'] } : { add: ['\\\\Flagged'] }\n );\n setMessages(prev =>\n prev.map(m =>\n m.uid === item.uid\n ? {\n ...m,\n flags: isFlagged ? m.flags.filter(f => f !== '\\\\Flagged') : [...m.flags, '\\\\Flagged'],\n }\n : m\n )\n );\n } catch (err) {\n toast.error(extractError(err));\n }\n }, [selectedFolderPath]);\n\n const trashMessage = useCallback(async (uid: number) => {\n try {\n await getMailClient().delete(`/api/mail/messages/${encodeURIComponent(selectedFolderPath)}/${uid}`);\n setMessages(prev => prev.filter(m => m.uid !== uid));\n if (selectedUid === uid) {\n setDetail(null);\n setSelectedUid(null);\n }\n } catch (err) {\n toast.error(extractError(err));\n }\n }, [selectedFolderPath, selectedUid]);\n\n function openCompose(initial?: DraftState) {\n setComposeDraft(initial ?? { to: '', cc: '', subject: '', body: '' });\n setComposeOpen(true);\n }\n\n if (serverReachable === false) {\n return (\n <EmptyState\n title=\"Mail server unreachable\"\n body=\"The bridge server is not responding. Start it with `npm run server:dev`, then retry.\"\n action={<button onClick={() => window.location.reload()} className=\"px-4 py-2 bg-gray-900 text-white rounded text-sm\">Retry</button>}\n />\n );\n }\n\n if (!isConnected) {\n return (\n <EmptyState\n title=\"Connect your mail account\"\n body=\"Open the Mail & Calendar button in the taskbar to connect via IMAP/SMTP/CalDAV.\"\n />\n );\n }\n\n return (\n <div className=\"flex h-full text-sm\">\n {/* Sidebar */}\n <aside className=\"w-56 shrink-0 border-r border-gray-200 overflow-y-auto bg-gray-50/60\">\n <div className=\"p-3\">\n <button\n onClick={() => openCompose()}\n className=\"w-full bg-gray-900 text-white rounded-lg px-3 py-2 text-sm font-medium hover:bg-gray-800\"\n >\n Compose\n </button>\n </div>\n <div className=\"px-2\">\n {SMART_VIEWS.map(view => {\n const folder = view.key === '__inbox__'\n ? folders.find(f => f.specialUse === 'inbox')\n : view.key === '__sent__'\n ? folders.find(f => f.specialUse === 'sent')\n : view.key === '__drafts__'\n ? folders.find(f => f.specialUse === 'drafts')\n : view.key === '__trash__'\n ? folders.find(f => f.specialUse === 'trash')\n : view.key === '__junk__'\n ? folders.find(f => f.specialUse === 'junk')\n : null;\n const unread = folder?.unreadCount ?? 0;\n const active = selectedKey === view.key;\n return (\n <button\n key={view.key}\n onClick={() => setSelectedKey(view.key)}\n className={`w-full flex items-center gap-2 px-2 py-1.5 rounded text-left text-sm ${active ? 'bg-gray-200 font-medium' : 'hover:bg-gray-100'}`}\n >\n <span className=\"w-5 text-center text-base leading-none\">{view.icon}</span>\n <span className=\"flex-1 truncate\">{view.label}</span>\n {unread > 0 && <span className=\"text-[10px] bg-blue-500 text-white rounded-full px-1.5\">{unread}</span>}\n </button>\n );\n })}\n </div>\n <div className=\"px-3 mt-4 mb-1 text-[10px] uppercase tracking-wider text-gray-500\">Folders</div>\n <div className=\"px-2 pb-3\">\n {folders\n .filter(f => !f.specialUse || f.specialUse === 'archive' || f.specialUse === 'flagged')\n .filter(f => f.path.toUpperCase() !== 'INBOX')\n .map(f => {\n const active = selectedKey === f.path;\n return (\n <button\n key={f.path}\n onClick={() => setSelectedKey(f.path)}\n className={`w-full flex items-center gap-2 px-2 py-1.5 rounded text-left text-sm ${active ? 'bg-gray-200 font-medium' : 'hover:bg-gray-100'}`}\n title={f.path}\n >\n <span className=\"w-5 text-center text-base leading-none\">📁</span>\n <span className=\"flex-1 truncate\">{f.name}</span>\n {f.unreadCount > 0 && <span className=\"text-[10px] bg-gray-300 text-gray-800 rounded-full px-1.5\">{f.unreadCount}</span>}\n </button>\n );\n })}\n </div>\n </aside>\n\n {/* Message list */}\n <section className=\"w-80 shrink-0 border-r border-gray-200 flex flex-col\">\n <header className=\"px-3 py-2 border-b border-gray-200 flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold\">\n {SMART_VIEWS.find(v => v.key === selectedKey)?.label || selectedKey}\n </h2>\n <button\n onClick={() => { refreshList(); refreshFolders(); }}\n className=\"text-xs text-gray-600 hover:text-gray-900\"\n disabled={loadingList || loadingFolders}\n >\n {loadingList || loadingFolders ? '…' : 'Refresh'}\n </button>\n </header>\n <div className=\"flex-1 overflow-y-auto\">\n {loadingList && messages.length === 0 ? (\n <div className=\"p-4 text-center text-xs text-gray-500\">Loading…</div>\n ) : messages.length === 0 ? (\n <div className=\"p-4 text-center text-xs text-gray-500\">No messages</div>\n ) : (\n messages.map(msg => (\n <MessageRow\n key={msg.uid}\n msg={msg}\n active={selectedUid === msg.uid}\n onOpen={() => openMessage(msg)}\n onStar={() => toggleStar(msg)}\n />\n ))\n )}\n </div>\n </section>\n\n {/* Detail */}\n <section className=\"flex-1 overflow-y-auto\">\n {detail ? (\n <MessageDetailView\n detail={detail}\n folderPath={selectedFolderPath}\n loading={loadingDetail}\n onReply={() => openCompose({\n to: detail.from.address,\n cc: '',\n subject: detail.subject.startsWith('Re:') ? detail.subject : `Re: ${detail.subject}`,\n body: '',\n inReplyTo: detail.threadId,\n references: detail.references,\n })}\n onTrash={() => trashMessage(detail.uid)}\n />\n ) : (\n <div className=\"h-full grid place-items-center text-xs text-gray-400\">\n Select a message\n </div>\n )}\n </section>\n\n {composeOpen && composeDraft && (\n <ComposeModal\n open={composeOpen}\n initial={composeDraft}\n onClose={() => setComposeOpen(false)}\n onSent={() => {\n setComposeOpen(false);\n toast.success('Message sent');\n refreshList();\n }}\n />\n )}\n\n {serverError && (\n <div className=\"absolute bottom-3 left-1/2 -translate-x-1/2 bg-red-50 border border-red-200 text-red-800 px-3 py-1 text-xs rounded\">\n {serverError}\n </div>\n )}\n </div>\n );\n}\n\nfunction MessageRow({ msg, active, onOpen, onStar }: {\n msg: MessageListItem;\n active: boolean;\n onOpen: () => void;\n onStar: () => void;\n}) {\n const unread = !msg.flags.includes('\\\\Seen');\n const starred = msg.flags.includes('\\\\Flagged');\n return (\n <div\n onClick={onOpen}\n className={`px-3 py-2 border-b border-gray-100 cursor-pointer ${active ? 'bg-blue-50' : 'hover:bg-gray-50'}`}\n >\n <div className=\"flex items-center gap-2 mb-0.5\">\n <button\n onClick={(e) => { e.stopPropagation(); onStar(); }}\n className={`text-xs ${starred ? 'text-yellow-500' : 'text-gray-300 hover:text-gray-500'}`}\n title={starred ? 'Unstar' : 'Star'}\n >\n ★\n </button>\n <p className={`text-xs flex-1 truncate ${unread ? 'font-semibold text-gray-900' : 'text-gray-700'}`}>\n {msg.from.name || msg.from.address}\n </p>\n <span className=\"text-[10px] text-gray-400 shrink-0\">{formatDate(msg.date)}</span>\n </div>\n <p className={`text-xs truncate ${unread ? 'font-medium text-gray-900' : 'text-gray-600'}`}>\n {msg.subject || '(no subject)'}\n </p>\n {msg.hasAttachments && <span className=\"text-[10px] text-gray-400\">📎 attachment</span>}\n </div>\n );\n}\n\nfunction MessageDetailView({\n detail,\n folderPath,\n loading,\n onReply,\n onTrash,\n}: {\n detail: MessageDetail;\n folderPath: string;\n loading: boolean;\n onReply: () => void;\n onTrash: () => void;\n}) {\n const baseUrl = `/api/mail/messages/${encodeURIComponent(folderPath)}/${detail.uid}/attachments`;\n return (\n <div>\n <header className=\"px-6 py-4 border-b border-gray-200\">\n <h1 className=\"text-lg font-semibold mb-2\">{detail.subject || '(no subject)'}</h1>\n <div className=\"flex items-center justify-between text-xs text-gray-600\">\n <div>\n <div><strong>{detail.from.name || detail.from.address}</strong> &lt;{detail.from.address}&gt;</div>\n <div>to {detail.to.map(t => t.address).join(', ')}</div>\n {detail.cc.length > 0 && <div>cc {detail.cc.map(t => t.address).join(', ')}</div>}\n <div className=\"text-gray-400 mt-1\">{formatDateTime(detail.date)}</div>\n </div>\n <div className=\"flex gap-2\">\n <button onClick={onReply} className=\"px-3 py-1 text-xs border border-gray-300 rounded hover:bg-gray-50\">Reply</button>\n <button onClick={onTrash} className=\"px-3 py-1 text-xs border border-red-200 text-red-700 rounded hover:bg-red-50\">Trash</button>\n </div>\n </div>\n </header>\n <article className=\"px-6 py-4\">\n {loading ? (\n <div className=\"text-xs text-gray-500\">Loading…</div>\n ) : detail.html ? (\n <div className=\"prose prose-sm max-w-none\" dangerouslySetInnerHTML={{ __html: detail.html }} />\n ) : (\n <pre className=\"whitespace-pre-wrap text-sm font-sans\">{detail.text || '(empty)'}</pre>\n )}\n </article>\n {detail.attachments.length > 0 && (\n <section className=\"px-6 pb-6\">\n <h3 className=\"text-xs font-semibold text-gray-700 mb-2\">Attachments</h3>\n <div className=\"grid grid-cols-2 gap-2\">\n {detail.attachments.map(att => (\n <a\n key={att.partId}\n href={`${getMailClient().defaults.baseURL}${baseUrl}/${encodeURIComponent(att.partId)}`}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"flex items-center gap-2 border border-gray-200 rounded px-3 py-2 text-xs hover:bg-gray-50\"\n >\n <span>📎</span>\n <span className=\"flex-1 truncate\">{att.filename}</span>\n <span className=\"text-gray-400\">{(att.size / 1024).toFixed(1)}KB</span>\n </a>\n ))}\n </div>\n </section>\n )}\n </div>\n );\n}\n\ninterface DraftState {\n to: string;\n cc: string;\n subject: string;\n body: string;\n inReplyTo?: string;\n references?: string[];\n}\n\nfunction ComposeModal({\n open,\n initial,\n onClose,\n onSent,\n}: {\n open: boolean;\n initial: DraftState;\n onClose: () => void;\n onSent: () => void;\n}) {\n const [draft, setDraft] = useState<DraftState>(initial);\n const [sending, setSending] = useState(false);\n\n async function send() {\n setSending(true);\n try {\n const toList = draft.to.split(',').map(s => s.trim()).filter(Boolean);\n const ccList = draft.cc.split(',').map(s => s.trim()).filter(Boolean);\n if (toList.length === 0) {\n toast.error('At least one recipient required');\n return;\n }\n await getMailClient().post('/api/mail/send', {\n to: toList,\n cc: ccList.length ? ccList : undefined,\n subject: draft.subject,\n text: draft.body,\n inReplyTo: draft.inReplyTo,\n references: draft.references,\n saveToSent: true,\n });\n onSent();\n } catch (err) {\n toast.error(extractError(err));\n } finally {\n setSending(false);\n }\n }\n\n return (\n <Modal open={open} onClose={onClose} title=\"New message\" size=\"lg\">\n <div className=\"space-y-3\">\n <input\n type=\"text\"\n placeholder=\"To\"\n value={draft.to}\n onChange={e => setDraft({ ...draft, to: e.target.value })}\n className=\"w-full border border-gray-300 rounded px-3 py-2 text-sm\"\n />\n <input\n type=\"text\"\n placeholder=\"Cc (optional)\"\n value={draft.cc}\n onChange={e => setDraft({ ...draft, cc: e.target.value })}\n className=\"w-full border border-gray-300 rounded px-3 py-2 text-sm\"\n />\n <input\n type=\"text\"\n placeholder=\"Subject\"\n value={draft.subject}\n onChange={e => setDraft({ ...draft, subject: e.target.value })}\n className=\"w-full border border-gray-300 rounded px-3 py-2 text-sm\"\n />\n <textarea\n rows={12}\n placeholder=\"Write your message…\"\n value={draft.body}\n onChange={e => setDraft({ ...draft, body: e.target.value })}\n className=\"w-full border border-gray-300 rounded px-3 py-2 text-sm font-mono\"\n />\n </div>\n <ModalActions>\n <button\n onClick={send}\n disabled={sending}\n className=\"bg-gray-900 text-white rounded-lg px-5 py-2 text-sm font-medium hover:bg-gray-800 disabled:opacity-50\"\n >\n {sending ? 'Sending…' : 'Send'}\n </button>\n </ModalActions>\n </Modal>\n );\n}\n\nfunction EmptyState({ title, body, action }: { title: string; body: string; action?: React.ReactNode }) {\n return (\n <div className=\"h-full grid place-items-center p-8 text-center\">\n <div className=\"max-w-sm\">\n <h2 className=\"text-lg font-semibold text-gray-900 mb-1\">{title}</h2>\n <p className=\"text-sm text-gray-600\">{body}</p>\n {action && <div className=\"mt-4\">{action}</div>}\n </div>\n </div>\n );\n}\n\nfunction extractError(err: unknown): string {\n const response = (err as { response?: { data?: { error?: string } } }).response;\n if (response?.data?.error) return response.data.error;\n if (err instanceof Error) return err.message;\n return 'Unknown error';\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/apps/_todoStore.ts"],"names":[],"mappings":"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","file":"chunk-FTL7F4TM.js","sourcesContent":["/**\n * Shared task store for the Todo List app, the Pomodoro widget and the\n * Calendar app — all three read/write the same list via `useTodoTasks()`.\n *\n * Two backends:\n * • Default: `useShellPrefs()` → `prefs.todo_tasks` (per-user prefs blob).\n * • Opt-in: a consumer-supplied `TodoProvider` registered with\n * `setShellTodoProvider(...)`. When set, the three apps read/write through\n * it instead — letting an ERP make the shell's tasks the SAME records as\n * its own task table, and tag each with a `contextLabel` badge (e.g.\n * \"Deal: Acme\"). Mirrors `setShellApiClient` / `setShellMailServer`.\n *\n * `migratePomodoroTasksOnce()` folds legacy `localStorage.pomodoro_tasks`\n * into the prefs store on first Pomodoro mount (no-op in provider mode).\n */\nimport { useCallback, useMemo, useSyncExternalStore } from 'react';\nimport { useShellPrefs } from '../shell/ShellPrefs';\nimport type { TodoTask } from './_todoTypes';\n\nconst POMODORO_LEGACY_KEY = 'pomodoro_tasks';\nconst POMODORO_LEGACY_MIGRATED_FLAG = 'pomodoro_tasks_migrated';\n\nfunction uid(): string {\n return Math.random().toString(36).slice(2, 11);\n}\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\nexport interface UseTodoTasks {\n tasks: TodoTask[];\n /** Add a new task. Returns the id of the freshly-added task. */\n addTask: (input: Partial<Omit<TodoTask, 'id' | 'createdAt' | 'updatedAt'>> & { name: string }) => string;\n /** Patch any subset of fields on a task by id. `updatedAt` is auto-bumped. */\n updateTask: (id: string, patch: Partial<TodoTask>) => void;\n /** Remove a task by id. Used by both Pomodoro's kebab menu and TodoList's delete action. */\n removeTask: (id: string) => void;\n /** Flip `done`. Same as `updateTask(id, { done: !done })` but faster to type at call sites. */\n toggleDone: (id: string) => void;\n /** Replace the entire list. Used by Google Tasks sync after a pull. */\n setAllTasks: (tasks: TodoTask[]) => void;\n}\n\n/**\n * A consumer-supplied task backend. Registering one (opt-in) routes every\n * shell task surface through it instead of the prefs blob. Methods map to/from\n * the shell's `TodoTask` shape, including the optional `source`/`contextLabel`.\n */\nexport interface TodoProvider {\n list(): Promise<TodoTask[]>;\n create(input: Partial<Omit<TodoTask, 'id' | 'createdAt' | 'updatedAt'>> & { name: string }): Promise<TodoTask>;\n update(id: string, patch: Partial<TodoTask>): Promise<TodoTask>;\n remove(id: string): Promise<void>;\n}\n\n// ── Module-level provider store (shared across all consumers) ──\nlet provider: TodoProvider | null = null;\nlet cache: TodoTask[] = [];\nlet loaded = false;\nlet inflight: Promise<void> | null = null;\nconst listeners = new Set<() => void>();\n\nfunction emit(): void {\n for (const l of listeners) l();\n}\n\nfunction setCache(next: TodoTask[]): void {\n cache = next;\n emit();\n}\n\nfunction refresh(): Promise<void> {\n const p = provider;\n if (!p) {\n cache = [];\n loaded = true;\n emit();\n return Promise.resolve();\n }\n inflight = p\n .list()\n .then(rows => {\n if (provider === p) {\n cache = rows;\n loaded = true;\n emit();\n }\n })\n .catch(() => {\n if (provider === p) {\n loaded = true;\n emit();\n }\n })\n .finally(() => {\n inflight = null;\n });\n return inflight;\n}\n\n/** Register (or clear with `null`) the backend task provider. Opt-in. */\nexport function setShellTodoProvider(next: TodoProvider | null): void {\n provider = next;\n cache = [];\n loaded = false;\n if (next) refresh();\n else emit();\n}\n\nexport function hasShellTodoProvider(): boolean {\n return provider !== null;\n}\n\nfunction subscribe(cb: () => void): () => void {\n listeners.add(cb);\n if (provider && !loaded && !inflight) refresh();\n return () => {\n listeners.delete(cb);\n };\n}\n\nfunction getSnapshot(): TodoTask[] {\n return cache;\n}\n\n// ── Prefs-backed implementation (default / fallback) ──\nfunction usePrefsTodoTasks(): UseTodoTasks {\n const { prefs, save } = useShellPrefs();\n const tasks: TodoTask[] = useMemo(() => {\n const raw = prefs.todo_tasks;\n return Array.isArray(raw) ? (raw as TodoTask[]) : [];\n }, [prefs.todo_tasks]);\n\n const writeTasks = useCallback((next: TodoTask[]) => {\n save({ todo_tasks: next });\n }, [save]);\n\n const addTask = useCallback<UseTodoTasks['addTask']>((input) => {\n const id = uid();\n const ts = nowIso();\n const task: TodoTask = { done: false, ...input, name: input.name.trim(), id, createdAt: ts, updatedAt: ts };\n writeTasks([...tasks, task]);\n return id;\n }, [tasks, writeTasks]);\n\n const updateTask = useCallback<UseTodoTasks['updateTask']>((id, patch) => {\n writeTasks(tasks.map(t => (t.id === id ? { ...t, ...patch, id: t.id, updatedAt: nowIso() } : t)));\n }, [tasks, writeTasks]);\n\n const removeTask = useCallback<UseTodoTasks['removeTask']>((id) => {\n writeTasks(tasks.filter(t => t.id !== id));\n }, [tasks, writeTasks]);\n\n const toggleDone = useCallback<UseTodoTasks['toggleDone']>((id) => {\n const target = tasks.find(t => t.id === id);\n if (target) updateTask(id, { done: !target.done });\n }, [tasks, updateTask]);\n\n return { tasks, addTask, updateTask, removeTask, toggleDone, setAllTasks: writeTasks };\n}\n\n// ── Public hook (provider-aware) ──\nexport function useTodoTasks(): UseTodoTasks {\n // Both hooks always run (rules of hooks); the active impl is chosen below.\n const prefsImpl = usePrefsTodoTasks();\n const providerTasks = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const addTask = useCallback<UseTodoTasks['addTask']>((input) => {\n const p = provider;\n if (!p) return prefsImpl.addTask(input);\n const tempId = 'tmp-' + uid();\n const ts = nowIso();\n const optimistic: TodoTask = { done: false, ...input, name: input.name.trim(), id: tempId, createdAt: ts, updatedAt: ts };\n setCache([...cache, optimistic]);\n p.create({ ...input, name: input.name.trim() })\n // Merge so server-owned fields win but client-only fields (estimated/\n // completed/notes the backend may not persist) survive the round-trip.\n .then(saved => setCache(cache.map(t => (t.id === tempId ? { ...optimistic, ...saved } : t))))\n .catch(() => setCache(cache.filter(t => t.id !== tempId)));\n return tempId;\n }, [prefsImpl]);\n\n const updateTask = useCallback<UseTodoTasks['updateTask']>((id, patch) => {\n const p = provider;\n if (!p) return prefsImpl.updateTask(id, patch);\n setCache(cache.map(t => (t.id === id ? { ...t, ...patch, id, updatedAt: nowIso() } : t)));\n p.update(id, patch).catch(() => { refresh(); });\n }, [prefsImpl]);\n\n const removeTask = useCallback<UseTodoTasks['removeTask']>((id) => {\n const p = provider;\n if (!p) return prefsImpl.removeTask(id);\n const prev = cache;\n setCache(cache.filter(t => t.id !== id));\n p.remove(id).catch(() => setCache(prev));\n }, [prefsImpl]);\n\n const toggleDone = useCallback<UseTodoTasks['toggleDone']>((id) => {\n if (!provider) return prefsImpl.toggleDone(id);\n const target = cache.find(t => t.id === id);\n if (target) updateTask(id, { done: !target.done });\n }, [prefsImpl, updateTask]);\n\n const setAllTasks = useCallback<UseTodoTasks['setAllTasks']>((next) => {\n // Provider owns persistence — bulk replace (Google Tasks sync) is a no-op there.\n if (!provider) prefsImpl.setAllTasks(next);\n }, [prefsImpl]);\n\n if (!hasShellTodoProvider()) return prefsImpl;\n return { tasks: providerTasks, addTask, updateTask, removeTask, toggleDone, setAllTasks };\n}\n\n/**\n * One-time migration: pull any tasks the Pomodoro widget previously\n * persisted to `localStorage.pomodoro_tasks` into the shared store.\n * No-op when a provider is registered (the provider owns persistence).\n */\nexport function migratePomodoroTasksOnce(\n currentTasks: TodoTask[],\n setAllTasks: (next: TodoTask[]) => void,\n): void {\n try {\n if (localStorage.getItem(POMODORO_LEGACY_MIGRATED_FLAG)) return;\n const raw = localStorage.getItem(POMODORO_LEGACY_KEY);\n if (!raw) {\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n return;\n }\n const legacy: Array<{ id?: string; name?: string; estimated?: number; completed?: number; done?: boolean }>\n = JSON.parse(raw);\n if (!Array.isArray(legacy) || legacy.length === 0) {\n localStorage.removeItem(POMODORO_LEGACY_KEY);\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n return;\n }\n const ts = nowIso();\n const migrated: TodoTask[] = legacy\n .filter(t => typeof t?.name === 'string')\n .map(t => ({\n id: t.id || uid(),\n name: String(t.name),\n done: !!t.done,\n estimated: typeof t.estimated === 'number' ? t.estimated : undefined,\n completed: typeof t.completed === 'number' ? t.completed : undefined,\n createdAt: ts,\n updatedAt: ts,\n }));\n const existingIds = new Set(currentTasks.map(t => t.id));\n const additions = migrated.filter(t => !existingIds.has(t.id));\n setAllTasks([...additions, ...currentTasks]);\n localStorage.removeItem(POMODORO_LEGACY_KEY);\n localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1');\n } catch {\n try { localStorage.setItem(POMODORO_LEGACY_MIGRATED_FLAG, '1'); } catch {}\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/date.ts"],"names":[],"mappings":";AAwBO,SAAS,iBAAA,GAAmC;AACjD,EAAA,OAAQ,YAAA,CAAa,OAAA,CAAQ,kBAAkB,CAAA,IAAuB,YAAA;AACxE;AAUO,SAAS,WAAW,KAAA,EAA0C;AACnE,EAAA,IAAI,CAAC,OAAO,OAAO,QAAA;AAEnB,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,QAAA,CAAS,GAAG,CAAA,GAAI,MAAM,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,GAAI,KAAA;AAC5D,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,QAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AAC/C,EAAA,IAAI,CAAC,CAAA,IAAK,CAAC,CAAA,IAAK,CAAC,GAAG,OAAO,KAAA;AAE3B,EAAA,MAAM,KAAK,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACpC,EAAA,MAAM,KAAK,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACpC,EAAA,MAAM,IAAA,GAAO,OAAO,CAAC,CAAA;AAErB,EAAA,MAAM,MAAM,iBAAA,EAAkB;AAC9B,EAAA,QAAQ,GAAA;AAAK,IACX,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,EAAE,IAAI,EAAE,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAA,IACL;AAAmB,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA;AAEjD;AAMO,SAAS,eAAe,KAAA,EAA0C;AACvE,EAAA,IAAI,CAAC,OAAO,OAAO,QAAA;AACnB,EAAA,MAAM,EAAA,GAAK,IAAI,IAAA,CAAK,KAAK,CAAA;AACzB,EAAA,IAAI,KAAA,CAAM,EAAA,CAAG,OAAA,EAAS,GAAG,OAAO,KAAA;AAChC,EAAA,MAAM,OAAA,GAAU,CAAA,EAAG,EAAA,CAAG,WAAA,EAAa,IAAI,MAAA,CAAO,EAAA,CAAG,QAAA,EAAS,GAAI,CAAC,CAAA,CAAE,SAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,EAAA,CAAG,OAAA,EAAS,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAC1H,EAAA,MAAM,IAAA,GAAO,GAAG,kBAAA,CAAmB,MAAA,EAAW,EAAE,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,SAAA,EAAW,CAAA;AACpF,EAAA,OAAO,CAAA,EAAG,UAAA,CAAW,OAAO,CAAC,KAAK,IAAI,CAAA,CAAA;AACxC","file":"chunk-NSU7OHPC.js","sourcesContent":["/**\n * Shared date formatting utility.\n *\n * Reads the user's preferred date format from localStorage (`user_date_format`)\n * and formats all dates consistently across the app.\n *\n * Supported formats:\n * 'DD/MM/YYYY' — 24/04/2026\n * 'MM/DD/YYYY' — 04/24/2026\n * 'YYYY-MM-DD' — 2026-04-24\n * 'DD-MM-YYYY' — 24-04-2026\n * 'DD.MM.YYYY' — 24.04.2026\n */\n\nexport type DateFormatKey = 'DD/MM/YYYY' | 'MM/DD/YYYY' | 'YYYY-MM-DD' | 'DD-MM-YYYY' | 'DD.MM.YYYY';\n\nexport const DATE_FORMAT_OPTIONS: { key: DateFormatKey; example: string }[] = [\n { key: 'DD/MM/YYYY', example: '24/04/2026' },\n { key: 'MM/DD/YYYY', example: '04/24/2026' },\n { key: 'YYYY-MM-DD', example: '2026-04-24' },\n { key: 'DD-MM-YYYY', example: '24-04-2026' },\n { key: 'DD.MM.YYYY', example: '24.04.2026' },\n];\n\nexport function getUserDateFormat(): DateFormatKey {\n return (localStorage.getItem('user_date_format') as DateFormatKey) || 'DD/MM/YYYY';\n}\n\nexport function setUserDateFormat(fmt: DateFormatKey) {\n localStorage.setItem('user_date_format', fmt);\n}\n\n/**\n * Format a date string (YYYY-MM-DD or ISO timestamp) for display.\n * Returns '—' for null/empty values.\n */\nexport function formatDate(value: string | null | undefined): string {\n if (!value) return '—';\n // Parse — handle both \"YYYY-MM-DD\" and ISO timestamps\n const dateStr = value.includes('T') ? value.split('T')[0] : value;\n const [y, m, d] = dateStr.split('-').map(Number);\n if (!y || !m || !d) return value; // fallback if unparseable\n\n const dd = String(d).padStart(2, '0');\n const mm = String(m).padStart(2, '0');\n const yyyy = String(y);\n\n const fmt = getUserDateFormat();\n switch (fmt) {\n case 'MM/DD/YYYY': return `${mm}/${dd}/${yyyy}`;\n case 'YYYY-MM-DD': return `${yyyy}-${mm}-${dd}`;\n case 'DD-MM-YYYY': return `${dd}-${mm}-${yyyy}`;\n case 'DD.MM.YYYY': return `${dd}.${mm}.${yyyy}`;\n case 'DD/MM/YYYY':\n default: return `${dd}/${mm}/${yyyy}`;\n }\n}\n\n/**\n * Format a datetime string (ISO timestamp) for display, including time.\n * Returns '—' for null/empty values.\n */\nexport function formatDateTime(value: string | null | undefined): string {\n if (!value) return '—';\n const dt = new Date(value);\n if (isNaN(dt.getTime())) return value;\n const dateStr = `${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, '0')}-${String(dt.getDate()).padStart(2, '0')}`;\n const time = dt.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n return `${formatDate(dateStr)}, ${time}`;\n}\n"]}
@@ -1,24 +0,0 @@
1
- import { useState, useEffect } from 'react';
2
-
3
- // src/hooks/useEmailUnread.ts
4
- var _count = 0;
5
- var _listeners = /* @__PURE__ */ new Set();
6
- function setEmailUnreadCount(n) {
7
- if (_count === n) return;
8
- _count = n;
9
- _listeners.forEach((fn) => fn(n));
10
- }
11
- function useEmailUnreadCount() {
12
- const [count, setCount] = useState(_count);
13
- useEffect(() => {
14
- _listeners.add(setCount);
15
- return () => {
16
- _listeners.delete(setCount);
17
- };
18
- }, []);
19
- return count;
20
- }
21
-
22
- export { setEmailUnreadCount, useEmailUnreadCount };
23
- //# sourceMappingURL=chunk-PDFQNHW7.js.map
24
- //# sourceMappingURL=chunk-PDFQNHW7.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/useEmailUnread.ts"],"names":[],"mappings":";;;AAEA,IAAI,MAAA,GAAS,CAAA;AACb,IAAM,UAAA,uBAAiB,GAAA,EAAyB;AAEzC,SAAS,oBAAoB,CAAA,EAAW;AAC7C,EAAA,IAAI,WAAW,CAAA,EAAG;AAClB,EAAA,MAAA,GAAS,CAAA;AACT,EAAA,UAAA,CAAW,OAAA,CAAQ,CAAA,EAAA,KAAM,EAAA,CAAG,CAAC,CAAC,CAAA;AAChC;AAEO,SAAS,mBAAA,GAA8B;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,MAAM,CAAA;AACzC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,UAAA,CAAW,IAAI,QAAQ,CAAA;AACvB,IAAA,OAAO,MAAM;AAAE,MAAA,UAAA,CAAW,OAAO,QAAQ,CAAA;AAAA,IAAG,CAAA;AAAA,EAC9C,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,OAAO,KAAA;AACT","file":"chunk-PDFQNHW7.js","sourcesContent":["import { useState, useEffect } from 'react';\n\nlet _count = 0;\nconst _listeners = new Set<(n: number) => void>();\n\nexport function setEmailUnreadCount(n: number) {\n if (_count === n) return;\n _count = n;\n _listeners.forEach(fn => fn(n));\n}\n\nexport function useEmailUnreadCount(): number {\n const [count, setCount] = useState(_count);\n useEffect(() => {\n _listeners.add(setCount);\n return () => { _listeners.delete(setCount); };\n }, []);\n return count;\n}\n"]}
@@ -1,129 +0,0 @@
1
- import { useState, useEffect, useCallback } from 'react';
2
-
3
- // src/api/mailClient.ts
4
- var DEFAULT_BASE_URL = "http://localhost:3001";
5
- var _client = null;
6
- var _baseUrl = DEFAULT_BASE_URL;
7
- var _axiosPromise = null;
8
- function loadAxios() {
9
- if (!_axiosPromise) _axiosPromise = import('axios').then((m) => m.default);
10
- return _axiosPromise;
11
- }
12
- async function setShellMailServer(input) {
13
- if (typeof input === "string") {
14
- _baseUrl = input;
15
- const axios = await loadAxios();
16
- _client = axios.create({ baseURL: input, withCredentials: true, timeout: 6e4 });
17
- } else {
18
- _client = input;
19
- }
20
- }
21
- function getMailClient() {
22
- if (_client) return _client;
23
- const proxy = new Proxy({}, {
24
- get(_t, prop) {
25
- if (typeof prop !== "string") return void 0;
26
- return (...args) => loadAxios().then((axios) => {
27
- if (!_client) {
28
- _client = axios.create({ baseURL: _baseUrl, withCredentials: true, timeout: 6e4 });
29
- }
30
- const fn = _client[prop];
31
- return typeof fn === "function" ? fn.apply(_client, args) : fn;
32
- });
33
- }
34
- });
35
- return proxy;
36
- }
37
- var SESSION_FLAG = "mail_session_known";
38
- var listeners = /* @__PURE__ */ new Set();
39
- var cached = {
40
- user: null,
41
- capabilities: null,
42
- checked: false,
43
- serverReachable: null
44
- };
45
- function broadcast() {
46
- listeners.forEach((fn) => fn());
47
- }
48
- async function fetchMe() {
49
- const client = getMailClient();
50
- try {
51
- const res = await client.get("/api/auth/me");
52
- cached = { user: res.data.user, capabilities: res.data.capabilities, checked: true, serverReachable: true };
53
- } catch (err) {
54
- const status = err?.response?.status;
55
- if (status === 401) {
56
- localStorage.removeItem(SESSION_FLAG);
57
- cached = { user: null, capabilities: null, checked: true, serverReachable: true };
58
- } else {
59
- cached = { user: null, capabilities: null, checked: true, serverReachable: false };
60
- }
61
- }
62
- broadcast();
63
- }
64
- function useMailAuth() {
65
- const [, force] = useState(0);
66
- const [loading, setLoading] = useState(false);
67
- const [error, setError] = useState(null);
68
- useEffect(() => {
69
- const sub = () => force((n) => n + 1);
70
- listeners.add(sub);
71
- if (!cached.checked && localStorage.getItem(SESSION_FLAG) === "true") {
72
- fetchMe();
73
- } else if (!cached.checked) {
74
- cached.checked = true;
75
- cached.serverReachable = null;
76
- broadcast();
77
- }
78
- return () => {
79
- listeners.delete(sub);
80
- };
81
- }, []);
82
- const login = useCallback(async (payload) => {
83
- setLoading(true);
84
- setError(null);
85
- try {
86
- const client = getMailClient();
87
- const res = await client.post("/api/auth/login", payload);
88
- localStorage.setItem(SESSION_FLAG, "true");
89
- cached = { user: res.data.user, capabilities: res.data.capabilities, checked: true, serverReachable: true };
90
- broadcast();
91
- } catch (err) {
92
- const msg = err?.response?.data?.error || err?.message || "Login failed";
93
- setError(msg);
94
- throw err;
95
- } finally {
96
- setLoading(false);
97
- }
98
- }, []);
99
- const logout = useCallback(async () => {
100
- setLoading(true);
101
- try {
102
- const client = getMailClient();
103
- await client.post("/api/auth/logout").catch(() => void 0);
104
- } finally {
105
- localStorage.removeItem(SESSION_FLAG);
106
- cached = { user: null, capabilities: null, checked: true, serverReachable: cached.serverReachable };
107
- setLoading(false);
108
- broadcast();
109
- }
110
- }, []);
111
- const refresh = useCallback(async () => {
112
- await fetchMe();
113
- }, []);
114
- return {
115
- loading,
116
- serverReachable: cached.serverReachable,
117
- isConnected: !!cached.user,
118
- user: cached.user,
119
- capabilities: cached.capabilities,
120
- error,
121
- login,
122
- logout,
123
- refresh
124
- };
125
- }
126
-
127
- export { getMailClient, setShellMailServer, useMailAuth };
128
- //# sourceMappingURL=chunk-VBFB3ZIN.js.map
129
- //# sourceMappingURL=chunk-VBFB3ZIN.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/mailClient.ts","../src/hooks/useMailAuth.ts"],"names":[],"mappings":";;;AAkBA,IAAM,gBAAA,GAAmB,uBAAA;AACzB,IAAI,OAAA,GAAgC,IAAA;AACpC,IAAI,QAAA,GAAmB,gBAAA;AACvB,IAAI,aAAA,GAAgE,IAAA;AAEpE,SAAS,SAAA,GAAqD;AAC5D,EAAA,IAAI,CAAC,aAAA,EAAe,aAAA,GAAgB,OAAO,OAAO,EAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAA;AACzE,EAAA,OAAO,aAAA;AACT;AAEA,eAAsB,mBAAmB,KAAA,EAA8C;AACrF,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,QAAA,GAAW,KAAA;AACX,IAAA,MAAM,KAAA,GAAQ,MAAM,SAAA,EAAU;AAC9B,IAAA,OAAA,GAAU,KAAA,CAAM,OAAO,EAAE,OAAA,EAAS,OAAO,eAAA,EAAiB,IAAA,EAAM,OAAA,EAAS,GAAA,EAAQ,CAAA;AAAA,EACnF,CAAA,MAAO;AACL,IAAA,OAAA,GAAU,KAAA;AAAA,EACZ;AACF;AAEO,SAAS,aAAA,GAA+B;AAC7C,EAAA,IAAI,SAAS,OAAO,OAAA;AAMpB,EAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,EAAC,EAAoB;AAAA,IAC3C,GAAA,CAAI,IAAI,IAAA,EAAM;AACZ,MAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,MAAA;AACrC,MAAA,OAAO,IAAI,IAAA,KACT,SAAA,EAAU,CAAE,IAAA,CAAK,CAAC,KAAA,KAAU;AAC1B,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA,OAAA,GAAU,KAAA,CAAM,OAAO,EAAE,OAAA,EAAS,UAAU,eAAA,EAAiB,IAAA,EAAM,OAAA,EAAS,GAAA,EAAQ,CAAA;AAAA,QACtF;AAEA,QAAA,MAAM,EAAA,GAAM,QAAgB,IAAI,CAAA;AAEhC,QAAA,OAAO,OAAO,EAAA,KAAO,UAAA,GAAa,GAAG,KAAA,CAAM,OAAA,EAAS,IAAI,CAAA,GAAI,EAAA;AAAA,MAC9D,CAAC,CAAA;AAAA,IACL;AAAA,GACD,CAAA;AACD,EAAA,OAAO,KAAA;AACT;AC1DA,IAAM,YAAA,GAAe,oBAAA;AA+BrB,IAAM,SAAA,uBAAgB,GAAA,EAAgB;AACtC,IAAI,MAAA,GAA8H;AAAA,EAChI,IAAA,EAAM,IAAA;AAAA,EACN,YAAA,EAAc,IAAA;AAAA,EACd,OAAA,EAAS,KAAA;AAAA,EACT,eAAA,EAAiB;AACnB,CAAA;AAEA,SAAS,SAAA,GAAkB;AACzB,EAAA,SAAA,CAAU,OAAA,CAAQ,CAAA,EAAA,KAAM,EAAA,EAAI,CAAA;AAC9B;AAEA,eAAe,OAAA,GAAyB;AACtC,EAAA,MAAM,SAAS,aAAA,EAAc;AAC7B,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,GAAA,CAAI,cAAc,CAAA;AAC3C,IAAA,MAAA,GAAS,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,IAAA,EAAM,YAAA,EAAc,GAAA,CAAI,IAAA,CAAK,YAAA,EAAc,OAAA,EAAS,IAAA,EAAM,eAAA,EAAiB,IAAA,EAAK;AAAA,EAC5G,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,MAAA,GAAU,KAA4C,QAAA,EAAU,MAAA;AACtE,IAAA,IAAI,WAAW,GAAA,EAAK;AAClB,MAAA,YAAA,CAAa,WAAW,YAAY,CAAA;AACpC,MAAA,MAAA,GAAS,EAAE,MAAM,IAAA,EAAM,YAAA,EAAc,MAAM,OAAA,EAAS,IAAA,EAAM,iBAAiB,IAAA,EAAK;AAAA,IAClF,CAAA,MAAO;AACL,MAAA,MAAA,GAAS,EAAE,MAAM,IAAA,EAAM,YAAA,EAAc,MAAM,OAAA,EAAS,IAAA,EAAM,iBAAiB,KAAA,EAAM;AAAA,IACnF;AAAA,EACF;AACA,EAAA,SAAA,EAAU;AACZ;AAEe,SAAR,WAAA,GAA8C;AACnD,EAAA,MAAM,GAAG,KAAK,CAAA,GAAI,SAAS,CAAC,CAAA;AAC5B,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAwB,IAAI,CAAA;AAEtD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,CAAA,CAAA,KAAK,IAAI,CAAC,CAAA;AAClC,IAAA,SAAA,CAAU,IAAI,GAAG,CAAA;AACjB,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,IAAW,aAAa,OAAA,CAAQ,YAAY,MAAM,MAAA,EAAQ;AACpE,MAAA,OAAA,EAAQ;AAAA,IACV,CAAA,MAAA,IAAW,CAAC,MAAA,CAAO,OAAA,EAAS;AAC1B,MAAA,MAAA,CAAO,OAAA,GAAU,IAAA;AACjB,MAAA,MAAA,CAAO,eAAA,GAAkB,IAAA;AACzB,MAAA,SAAA,EAAU;AAAA,IACZ;AACA,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,CAAU,OAAO,GAAG,CAAA;AAAA,IACtB,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,OAAO,OAAA,KAA0B;AACzD,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,aAAA,EAAc;AAC7B,MAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,IAAA,CAAK,mBAAmB,OAAO,CAAA;AACxD,MAAA,YAAA,CAAa,OAAA,CAAQ,cAAc,MAAM,CAAA;AACzC,MAAA,MAAA,GAAS,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,IAAA,EAAM,YAAA,EAAc,GAAA,CAAI,IAAA,CAAK,YAAA,EAAc,OAAA,EAAS,IAAA,EAAM,eAAA,EAAiB,IAAA,EAAK;AAC1G,MAAA,SAAA,EAAU;AAAA,IACZ,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,MAAO,GAAA,EAAwE,QAAA,EAAU,IAAA,EAAM,KAAA,IAC/F,KAA8B,OAAA,IAC/B,cAAA;AACL,MAAA,QAAA,CAAS,GAAG,CAAA;AACZ,MAAA,MAAM,GAAA;AAAA,IACR,CAAA,SAAE;AACA,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAClB;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,MAAA,GAAS,YAAY,YAAY;AACrC,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,aAAA,EAAc;AAC7B,MAAA,MAAM,OAAO,IAAA,CAAK,kBAAkB,CAAA,CAAE,KAAA,CAAM,MAAM,KAAA,CAAS,CAAA;AAAA,IAC7D,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,WAAW,YAAY,CAAA;AACpC,MAAA,MAAA,GAAS,EAAE,MAAM,IAAA,EAAM,YAAA,EAAc,MAAM,OAAA,EAAS,IAAA,EAAM,eAAA,EAAiB,MAAA,CAAO,eAAA,EAAgB;AAClG,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA,SAAA,EAAU;AAAA,IACZ;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,OAAA,GAAU,YAAY,YAAY;AACtC,IAAA,MAAM,OAAA,EAAQ;AAAA,EAChB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,iBAAiB,MAAA,CAAO,eAAA;AAAA,IACxB,WAAA,EAAa,CAAC,CAAC,MAAA,CAAO,IAAA;AAAA,IACtB,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,cAAc,MAAA,CAAO,YAAA;AAAA,IACrB,KAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AACF","file":"chunk-VBFB3ZIN.js","sourcesContent":["// Mail bridge client.\n//\n// Axios is imported dynamically (via `import('axios')`) so the shell's static\n// module graph never references it. Consumers (e.g. admin-portal) bundle\n// their own axios for their own API client — when both the shell and the\n// host statically reference axios, rolldown puts it in a shared chunk and\n// occasionally orders that chunk after the consumer's `client.ts` chunk,\n// surfacing as `Cannot read properties of undefined (reading 'create')`\n// during module evaluation (see 0.3.0 → 0.3.1 prod incident). Keeping the\n// runtime import here lazy avoids that entire chunk-graph by design.\n//\n// `getMailClient()` keeps its synchronous signature by returning a Proxy\n// that resolves axios on first method call; existing callers that already\n// `await client.get(...)` keep working unchanged because the proxied method\n// returns the same Promise shape.\n\nimport type { AxiosInstance } from 'axios';\n\nconst DEFAULT_BASE_URL = 'http://localhost:3001';\nlet _client: AxiosInstance | null = null;\nlet _baseUrl: string = DEFAULT_BASE_URL;\nlet _axiosPromise: Promise<typeof import('axios').default> | null = null;\n\nfunction loadAxios(): Promise<typeof import('axios').default> {\n if (!_axiosPromise) _axiosPromise = import('axios').then((m) => m.default);\n return _axiosPromise;\n}\n\nexport async function setShellMailServer(input: string | AxiosInstance): Promise<void> {\n if (typeof input === 'string') {\n _baseUrl = input;\n const axios = await loadAxios();\n _client = axios.create({ baseURL: input, withCredentials: true, timeout: 60_000 });\n } else {\n _client = input;\n }\n}\n\nexport function getMailClient(): AxiosInstance {\n if (_client) return _client;\n\n // Lazy proxy: resolves axios + creates the instance on first method call.\n // Methods that return promises (the entire AxiosInstance surface) keep\n // their normal signature — callers `await client.get(...)` exactly as\n // before. Non-method property access returns undefined.\n const proxy = new Proxy({} as AxiosInstance, {\n get(_t, prop) {\n if (typeof prop !== 'string') return undefined;\n return (...args: unknown[]) =>\n loadAxios().then((axios) => {\n if (!_client) {\n _client = axios.create({ baseURL: _baseUrl, withCredentials: true, timeout: 60_000 });\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const fn = (_client as any)[prop];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return typeof fn === 'function' ? fn.apply(_client, args) : fn;\n });\n },\n });\n return proxy;\n}\n\nexport function getMailServerBaseUrl(): string {\n return _baseUrl;\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { getMailClient } from '../api/mailClient';\n\nconst SESSION_FLAG = 'mail_session_known';\n\nexport interface MailUser {\n email: string;\n displayName: string;\n}\n\nexport interface MailCapabilities {\n imap: { thread: boolean; condstore: boolean; idle: boolean };\n smtp: boolean;\n caldav: boolean;\n}\n\nexport interface LoginPayload {\n imap: { host: string; port: number; secure: boolean; user: string; pass: string };\n smtp: { host: string; port: number; secure: boolean; user: string; pass: string };\n caldav?: { serverUrl: string; user: string; pass: string };\n}\n\ninterface MailAuthState {\n loading: boolean;\n serverReachable: boolean | null;\n isConnected: boolean;\n user: MailUser | null;\n capabilities: MailCapabilities | null;\n error: string | null;\n login: (payload: LoginPayload) => Promise<void>;\n logout: () => Promise<void>;\n refresh: () => Promise<void>;\n}\n\nconst listeners = new Set<() => void>();\nlet cached: { user: MailUser | null; capabilities: MailCapabilities | null; checked: boolean; serverReachable: boolean | null } = {\n user: null,\n capabilities: null,\n checked: false,\n serverReachable: null,\n};\n\nfunction broadcast(): void {\n listeners.forEach(fn => fn());\n}\n\nasync function fetchMe(): Promise<void> {\n const client = getMailClient();\n try {\n const res = await client.get('/api/auth/me');\n cached = { user: res.data.user, capabilities: res.data.capabilities, checked: true, serverReachable: true };\n } catch (err) {\n const status = (err as { response?: { status?: number } })?.response?.status;\n if (status === 401) {\n localStorage.removeItem(SESSION_FLAG);\n cached = { user: null, capabilities: null, checked: true, serverReachable: true };\n } else {\n cached = { user: null, capabilities: null, checked: true, serverReachable: false };\n }\n }\n broadcast();\n}\n\nexport default function useMailAuth(): MailAuthState {\n const [, force] = useState(0);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const sub = () => force(n => n + 1);\n listeners.add(sub);\n if (!cached.checked && localStorage.getItem(SESSION_FLAG) === 'true') {\n fetchMe();\n } else if (!cached.checked) {\n cached.checked = true;\n cached.serverReachable = null;\n broadcast();\n }\n return () => {\n listeners.delete(sub);\n };\n }, []);\n\n const login = useCallback(async (payload: LoginPayload) => {\n setLoading(true);\n setError(null);\n try {\n const client = getMailClient();\n const res = await client.post('/api/auth/login', payload);\n localStorage.setItem(SESSION_FLAG, 'true');\n cached = { user: res.data.user, capabilities: res.data.capabilities, checked: true, serverReachable: true };\n broadcast();\n } catch (err) {\n const msg = (err as { response?: { data?: { error?: string } }; message?: string })?.response?.data?.error\n || (err as { message?: string })?.message\n || 'Login failed';\n setError(msg);\n throw err;\n } finally {\n setLoading(false);\n }\n }, []);\n\n const logout = useCallback(async () => {\n setLoading(true);\n try {\n const client = getMailClient();\n await client.post('/api/auth/logout').catch(() => undefined);\n } finally {\n localStorage.removeItem(SESSION_FLAG);\n cached = { user: null, capabilities: null, checked: true, serverReachable: cached.serverReachable };\n setLoading(false);\n broadcast();\n }\n }, []);\n\n const refresh = useCallback(async () => {\n await fetchMe();\n }, []);\n\n return {\n loading,\n serverReachable: cached.serverReachable,\n isConnected: !!cached.user,\n user: cached.user,\n capabilities: cached.capabilities,\n error,\n login,\n logout,\n refresh,\n };\n}\n"]}