react-os-shell 0.3.1 → 0.3.3

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.
Files changed (51) hide show
  1. package/dist/{Browser-H5KDP5OH.js → Browser-3YRKFDQH.js} +3 -3
  2. package/dist/{Browser-H5KDP5OH.js.map → Browser-3YRKFDQH.js.map} +1 -1
  3. package/dist/{Calculator-QQ7NF53Q.js → Calculator-I6STIEPX.js} +4 -4
  4. package/dist/{Calculator-QQ7NF53Q.js.map → Calculator-I6STIEPX.js.map} +1 -1
  5. package/dist/{Calendar-J6L7FGHS.js → Calendar-5SYINMRN.js} +4 -4
  6. package/dist/{Calendar-J6L7FGHS.js.map → Calendar-5SYINMRN.js.map} +1 -1
  7. package/dist/{CurrencyConverter-YHOGBUPH.js → CurrencyConverter-S7ZIGW32.js} +4 -4
  8. package/dist/{CurrencyConverter-YHOGBUPH.js.map → CurrencyConverter-S7ZIGW32.js.map} +1 -1
  9. package/dist/{Documents-6DYALASM.js → Documents-4DWKHYJ2.js} +3 -3
  10. package/dist/{Documents-6DYALASM.js.map → Documents-4DWKHYJ2.js.map} +1 -1
  11. package/dist/{Email-U2U5Z4DL.js → Email-NFDNYPHW.js} +4 -4
  12. package/dist/{Email-U2U5Z4DL.js.map → Email-NFDNYPHW.js.map} +1 -1
  13. package/dist/Files-GNXHSGOT.js +11 -0
  14. package/dist/{Files-T62M4V5I.js.map → Files-GNXHSGOT.js.map} +1 -1
  15. package/dist/{Minesweeper-S2JHXYLX.js → Minesweeper-HAVR3WDR.js} +3 -3
  16. package/dist/{Minesweeper-S2JHXYLX.js.map → Minesweeper-HAVR3WDR.js.map} +1 -1
  17. package/dist/{Notepad-2YF7X3XO.js → Notepad-42RYNIWU.js} +3 -3
  18. package/dist/{Notepad-2YF7X3XO.js.map → Notepad-42RYNIWU.js.map} +1 -1
  19. package/dist/{PomodoroTimer-3J7Z3NVQ.js → PomodoroTimer-TCNRFYBB.js} +4 -4
  20. package/dist/{PomodoroTimer-3J7Z3NVQ.js.map → PomodoroTimer-TCNRFYBB.js.map} +1 -1
  21. package/dist/Preview-ZMKX7HEL.js +8 -0
  22. package/dist/{Preview-WM6ZP5PZ.js.map → Preview-ZMKX7HEL.js.map} +1 -1
  23. package/dist/Spreadsheet-7VTXFG4O.js +6 -0
  24. package/dist/{Spreadsheet-ZIE2SXAF.js.map → Spreadsheet-7VTXFG4O.js.map} +1 -1
  25. package/dist/{Weather-2GFPSZ5V.js → Weather-KRRBDBZI.js} +4 -4
  26. package/dist/{Weather-2GFPSZ5V.js.map → Weather-KRRBDBZI.js.map} +1 -1
  27. package/dist/{WorldClock-P4JR5I6X.js → WorldClock-RRNDO2JY.js} +4 -4
  28. package/dist/{WorldClock-P4JR5I6X.js.map → WorldClock-RRNDO2JY.js.map} +1 -1
  29. package/dist/apps/index.js +19 -19
  30. package/dist/{chunk-ZBRFMK3E.js → chunk-DUOC7DVH.js} +4 -4
  31. package/dist/{chunk-ZBRFMK3E.js.map → chunk-DUOC7DVH.js.map} +1 -1
  32. package/dist/{chunk-ATQVRDDQ.js → chunk-EZ7BNGAJ.js} +3 -3
  33. package/dist/{chunk-ATQVRDDQ.js.map → chunk-EZ7BNGAJ.js.map} +1 -1
  34. package/dist/{chunk-KMGWSDEI.js → chunk-HY2HAQCE.js} +3 -3
  35. package/dist/{chunk-KMGWSDEI.js.map → chunk-HY2HAQCE.js.map} +1 -1
  36. package/dist/{chunk-SEV7UXGN.js → chunk-JOCSHP4S.js} +4 -4
  37. package/dist/{chunk-SEV7UXGN.js.map → chunk-JOCSHP4S.js.map} +1 -1
  38. package/dist/{chunk-62FC2FHC.js → chunk-QKSQ6LOL.js} +4 -3
  39. package/dist/chunk-QKSQ6LOL.js.map +1 -0
  40. package/dist/{chunk-O6FJZAFM.js → chunk-UT4QQGUK.js} +3 -3
  41. package/dist/{chunk-O6FJZAFM.js.map → chunk-UT4QQGUK.js.map} +1 -1
  42. package/dist/{chunk-57B3WALN.js → chunk-VBFB3ZIN.js} +23 -8
  43. package/dist/chunk-VBFB3ZIN.js.map +1 -0
  44. package/dist/index.d.ts +1 -1
  45. package/dist/index.js +8 -8
  46. package/package.json +1 -1
  47. package/dist/Files-T62M4V5I.js +0 -11
  48. package/dist/Preview-WM6ZP5PZ.js +0 -8
  49. package/dist/Spreadsheet-ZIE2SXAF.js +0 -6
  50. package/dist/chunk-57B3WALN.js.map +0 -1
  51. package/dist/chunk-62FC2FHC.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { Modal } from './chunk-62FC2FHC.js';
1
+ import { Modal } from './chunk-QKSQ6LOL.js';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
 
4
4
  var DEFAULT_APPEARANCE = { activeOpacity: 70, inactiveOpacity: 50, activeBlur: 0, inactiveBlur: 0 };
@@ -138,5 +138,5 @@ function WidgetSettingsModal({ open, onClose, title, appearance, onAppearanceCha
138
138
  }
139
139
 
140
140
  export { WidgetSettingsModal, loadAppearance };
141
- //# sourceMappingURL=chunk-O6FJZAFM.js.map
142
- //# sourceMappingURL=chunk-O6FJZAFM.js.map
141
+ //# sourceMappingURL=chunk-UT4QQGUK.js.map
142
+ //# sourceMappingURL=chunk-UT4QQGUK.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shell/WidgetSettingsModal.tsx"],"names":[],"mappings":"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","file":"chunk-O6FJZAFM.js","sourcesContent":["import Modal from './Modal';\n\nexport interface WidgetAppearance {\n activeOpacity: number;\n inactiveOpacity: number;\n activeBlur: number;\n inactiveBlur: number;\n}\n\nexport const DEFAULT_APPEARANCE: WidgetAppearance = { activeOpacity: 70, inactiveOpacity: 50, activeBlur: 0, inactiveBlur: 0 };\n\nexport function loadAppearance(key: string): WidgetAppearance {\n try {\n const saved = JSON.parse(localStorage.getItem(key) || '');\n // Migrate old single `blur` field to activeBlur/inactiveBlur\n if (saved.blur != null && saved.activeBlur == null) {\n saved.activeBlur = saved.blur;\n saved.inactiveBlur = saved.blur;\n delete saved.blur;\n }\n return { ...DEFAULT_APPEARANCE, ...saved };\n }\n catch { return DEFAULT_APPEARANCE; }\n}\n\n/** Reusable settings modal for widgets — renders appearance sliders + optional extra content above */\nexport default function WidgetSettingsModal({ open, onClose, title, appearance, onAppearanceChange, onSave, children }: {\n open: boolean;\n onClose: () => void;\n title: string;\n appearance: WidgetAppearance;\n onAppearanceChange: (a: WidgetAppearance) => void;\n onSave: () => void;\n children?: React.ReactNode;\n}) {\n if (!open) return null;\n\n const inp = 'w-full h-1.5 rounded-full appearance-none bg-gray-200 cursor-pointer accent-blue-500';\n const lbl = 'flex items-center justify-between text-xs text-gray-500';\n\n return (\n <div onPointerDown={e => e.stopPropagation()} onContextMenu={e => e.stopPropagation()}>\n <Modal open={open} onClose={onClose} title={title} size=\"sm\">\n <div className=\"space-y-4\">\n {children}\n\n {/* Appearance */}\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-3\">Appearance</h3>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Active</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.activeOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.activeOpacity}\n onChange={e => onAppearanceChange({ ...appearance, activeOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.activeBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.activeBlur}\n onChange={e => onAppearanceChange({ ...appearance, activeBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Inactive</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.inactiveOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.inactiveOpacity}\n onChange={e => onAppearanceChange({ ...appearance, inactiveOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.inactiveBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.inactiveBlur}\n onChange={e => onAppearanceChange({ ...appearance, inactiveBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex gap-2 pt-2\">\n <button onClick={onSave}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition\">Save</button>\n <button onClick={onClose}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg border border-gray-300 text-gray-600 hover:bg-gray-50 transition\">Cancel</button>\n </div>\n </div>\n </Modal>\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/shell/WidgetSettingsModal.tsx"],"names":[],"mappings":"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","file":"chunk-UT4QQGUK.js","sourcesContent":["import Modal from './Modal';\n\nexport interface WidgetAppearance {\n activeOpacity: number;\n inactiveOpacity: number;\n activeBlur: number;\n inactiveBlur: number;\n}\n\nexport const DEFAULT_APPEARANCE: WidgetAppearance = { activeOpacity: 70, inactiveOpacity: 50, activeBlur: 0, inactiveBlur: 0 };\n\nexport function loadAppearance(key: string): WidgetAppearance {\n try {\n const saved = JSON.parse(localStorage.getItem(key) || '');\n // Migrate old single `blur` field to activeBlur/inactiveBlur\n if (saved.blur != null && saved.activeBlur == null) {\n saved.activeBlur = saved.blur;\n saved.inactiveBlur = saved.blur;\n delete saved.blur;\n }\n return { ...DEFAULT_APPEARANCE, ...saved };\n }\n catch { return DEFAULT_APPEARANCE; }\n}\n\n/** Reusable settings modal for widgets — renders appearance sliders + optional extra content above */\nexport default function WidgetSettingsModal({ open, onClose, title, appearance, onAppearanceChange, onSave, children }: {\n open: boolean;\n onClose: () => void;\n title: string;\n appearance: WidgetAppearance;\n onAppearanceChange: (a: WidgetAppearance) => void;\n onSave: () => void;\n children?: React.ReactNode;\n}) {\n if (!open) return null;\n\n const inp = 'w-full h-1.5 rounded-full appearance-none bg-gray-200 cursor-pointer accent-blue-500';\n const lbl = 'flex items-center justify-between text-xs text-gray-500';\n\n return (\n <div onPointerDown={e => e.stopPropagation()} onContextMenu={e => e.stopPropagation()}>\n <Modal open={open} onClose={onClose} title={title} size=\"sm\">\n <div className=\"space-y-4\">\n {children}\n\n {/* Appearance */}\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-3\">Appearance</h3>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Active</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.activeOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.activeOpacity}\n onChange={e => onAppearanceChange({ ...appearance, activeOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.activeBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.activeBlur}\n onChange={e => onAppearanceChange({ ...appearance, activeBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Inactive</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.inactiveOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.inactiveOpacity}\n onChange={e => onAppearanceChange({ ...appearance, inactiveOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.inactiveBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.inactiveBlur}\n onChange={e => onAppearanceChange({ ...appearance, inactiveBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex gap-2 pt-2\">\n <button onClick={onSave}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition\">Save</button>\n <button onClick={onClose}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg border border-gray-300 text-gray-600 hover:bg-gray-50 transition\">Cancel</button>\n </div>\n </div>\n </Modal>\n </div>\n );\n}\n"]}
@@ -1,23 +1,38 @@
1
- import axios from 'axios';
2
1
  import { useState, useEffect, useCallback } from 'react';
3
2
 
4
3
  // src/api/mailClient.ts
5
4
  var DEFAULT_BASE_URL = "http://localhost:3001";
6
5
  var _client = null;
7
6
  var _baseUrl = DEFAULT_BASE_URL;
8
- function setShellMailServer(input) {
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) {
9
13
  if (typeof input === "string") {
10
14
  _baseUrl = input;
15
+ const axios = await loadAxios();
11
16
  _client = axios.create({ baseURL: input, withCredentials: true, timeout: 6e4 });
12
17
  } else {
13
18
  _client = input;
14
19
  }
15
20
  }
16
21
  function getMailClient() {
17
- if (!_client) {
18
- _client = axios.create({ baseURL: _baseUrl, withCredentials: true, timeout: 6e4 });
19
- }
20
- return _client;
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;
21
36
  }
22
37
  var SESSION_FLAG = "mail_session_known";
23
38
  var listeners = /* @__PURE__ */ new Set();
@@ -110,5 +125,5 @@ function useMailAuth() {
110
125
  }
111
126
 
112
127
  export { getMailClient, setShellMailServer, useMailAuth };
113
- //# sourceMappingURL=chunk-57B3WALN.js.map
114
- //# sourceMappingURL=chunk-57B3WALN.js.map
128
+ //# sourceMappingURL=chunk-VBFB3ZIN.js.map
129
+ //# sourceMappingURL=chunk-VBFB3ZIN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/mailClient.ts","../src/hooks/useMailAuth.ts"],"names":[],"mappings":"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","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"]}
package/dist/index.d.ts CHANGED
@@ -805,7 +805,7 @@ declare function useShellEntityFetcher(): EntityFetcher;
805
805
  * they use elsewhere. The package only delegates HTTP to this. */
806
806
  declare function setShellApiClient(instance: AxiosInstance): void;
807
807
 
808
- declare function setShellMailServer(input: string | AxiosInstance): void;
808
+ declare function setShellMailServer(input: string | AxiosInstance): Promise<void>;
809
809
 
810
810
  interface ShellUser {
811
811
  email?: string;
package/dist/index.js CHANGED
@@ -1,20 +1,20 @@
1
1
  import { useEmailUnreadCount } from './chunk-PDFQNHW7.js';
2
2
  import { formatDate } from './chunk-NSU7OHPC.js';
3
3
  export { formatDate } from './chunk-NSU7OHPC.js';
4
- import { useMailAuth } from './chunk-57B3WALN.js';
5
- export { setShellMailServer, useMailAuth } from './chunk-57B3WALN.js';
4
+ import { useMailAuth } from './chunk-VBFB3ZIN.js';
5
+ export { setShellMailServer, useMailAuth } from './chunk-VBFB3ZIN.js';
6
6
  import { subscribePomo, getPomoSnapshot } from './chunk-MK3HLUO4.js';
7
7
  import { useShellPrefs } from './chunk-36VM54SC.js';
8
8
  export { ShellPrefsProvider, useLocalStoragePrefs, useShellPrefs } from './chunk-36VM54SC.js';
9
- import { PREVIEW_OPENED_EVENT, openPreviewFile } from './chunk-ZBRFMK3E.js';
9
+ import { PREVIEW_OPENED_EVENT, openPreviewFile } from './chunk-DUOC7DVH.js';
10
10
  import { playNotification, playStartup, soundsEnabled, getSoundConfig, SOUND_PACK_KEYS, SOUND_PACKS, SOUND_TYPES, SOUND_TYPE_LABELS, playLogout, setSoundForType, previewSound, setAllSounds } from './chunk-D7PYW2QS.js';
11
- import { setPdfPreview } from './chunk-ATQVRDDQ.js';
11
+ import { setPdfPreview } from './chunk-EZ7BNGAJ.js';
12
12
  import './chunk-KUIPWCTJ.js';
13
13
  import { toast_default } from './chunk-WIJ45SYD.js';
14
14
  export { toast_default as toast } from './chunk-WIJ45SYD.js';
15
- export { EditableGrid } from './chunk-KMGWSDEI.js';
16
- import { useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, Modal, ModalActions, useIsMobile, useModalActive, WINDOW_REGISTRY, isPageEntry, LoadingSpinner, ThumbCard, activateModal } from './chunk-62FC2FHC.js';
17
- export { CancelButton, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, WindowManagerProvider, WindowTitle, commitExposeHighlight, exitExposeMode, getActiveWindowRoute, getExposeHighlight, isEntityEntry, isPageEntry, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, subscribeExposeHighlight, toggleExposeMode, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-62FC2FHC.js';
15
+ export { EditableGrid } from './chunk-HY2HAQCE.js';
16
+ import { useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, Modal, ModalActions, useIsMobile, useModalActive, WINDOW_REGISTRY, isPageEntry, LoadingSpinner, ThumbCard, activateModal } from './chunk-QKSQ6LOL.js';
17
+ export { CancelButton, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, WindowManagerProvider, WindowTitle, commitExposeHighlight, exitExposeMode, getActiveWindowRoute, getExposeHighlight, isEntityEntry, isPageEntry, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, subscribeExposeHighlight, toggleExposeMode, useModalActive, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-QKSQ6LOL.js';
18
18
  import { confirm } from './chunk-PLGHQ7QW.js';
19
19
  export { ConfirmProvider, confirm, confirmDestructive, prompt } from './chunk-PLGHQ7QW.js';
20
20
  import { useAuth } from './chunk-ADJ3CERD.js';
@@ -915,7 +915,7 @@ function StatusBadge({ status }) {
915
915
  }
916
916
 
917
917
  // src/version.ts
918
- var VERSION = "0.3.1" ;
918
+ var VERSION = "0.3.3" ;
919
919
  var APP_VERSION = VERSION;
920
920
 
921
921
  // src/changelog.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-os-shell",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Desktop-style React UI shell — windows, taskbar, start menu, sticky notes, frosted glass theming, and bundled apps. Email + Calendar talk to your own IMAP/SMTP/CalDAV provider via a colocated Node bridge server.",
5
5
  "license": "MIT",
6
6
  "author": "Victor Y. Mau",
@@ -1,11 +0,0 @@
1
- export { Files as default, openFilesInTrashMode } from './chunk-SEV7UXGN.js';
2
- import './chunk-ZBRFMK3E.js';
3
- import './chunk-ATQVRDDQ.js';
4
- import './chunk-KUIPWCTJ.js';
5
- import './chunk-WIJ45SYD.js';
6
- import './chunk-KMGWSDEI.js';
7
- import './chunk-62FC2FHC.js';
8
- import './chunk-PLGHQ7QW.js';
9
- import './chunk-SSA762W5.js';
10
- //# sourceMappingURL=Files-T62M4V5I.js.map
11
- //# sourceMappingURL=Files-T62M4V5I.js.map
@@ -1,8 +0,0 @@
1
- export { Preview as default, setPdfPreview } from './chunk-ATQVRDDQ.js';
2
- import './chunk-KUIPWCTJ.js';
3
- import './chunk-WIJ45SYD.js';
4
- import './chunk-62FC2FHC.js';
5
- import './chunk-PLGHQ7QW.js';
6
- import './chunk-SSA762W5.js';
7
- //# sourceMappingURL=Preview-WM6ZP5PZ.js.map
8
- //# sourceMappingURL=Preview-WM6ZP5PZ.js.map
@@ -1,6 +0,0 @@
1
- export { Spreadsheet as default, setSpreadsheetPreview } from './chunk-KMGWSDEI.js';
2
- import './chunk-62FC2FHC.js';
3
- import './chunk-PLGHQ7QW.js';
4
- import './chunk-SSA762W5.js';
5
- //# sourceMappingURL=Spreadsheet-ZIE2SXAF.js.map
6
- //# sourceMappingURL=Spreadsheet-ZIE2SXAF.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/mailClient.ts","../src/hooks/useMailAuth.ts"],"names":[],"mappings":"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","file":"chunk-57B3WALN.js","sourcesContent":["import axios, { type AxiosInstance } from 'axios';\n\nconst DEFAULT_BASE_URL = 'http://localhost:3001';\nlet _client: AxiosInstance | null = null;\nlet _baseUrl: string = DEFAULT_BASE_URL;\n\nexport function setShellMailServer(input: string | AxiosInstance): void {\n if (typeof input === 'string') {\n _baseUrl = input;\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) {\n _client = axios.create({ baseURL: _baseUrl, withCredentials: true, timeout: 60_000 });\n }\n return _client;\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"]}