diff --git a/electron/main.cjs b/electron/main.cjs index 429f91b..39e9733 100644 --- a/electron/main.cjs +++ b/electron/main.cjs @@ -54,10 +54,14 @@ function getStoredCredentials() { function writeCredentials(credentials) { if (!safeStorage.isEncryptionAvailable()) { - throw new Error('Secure credential storage is not available on this system') + throw new Error('macOS Keychain is locked or unavailable. Unlock Keychain and try signing in again.') + } + try { + const encrypted = safeStorage.encryptString(JSON.stringify(credentials)) + fs.writeFileSync(userDataPath(credentialFileName), encrypted) + } catch (err) { + throw new Error(`Could not save credentials to secure storage: ${err.message || err}`) } - const encrypted = safeStorage.encryptString(JSON.stringify(credentials)) - fs.writeFileSync(userDataPath(credentialFileName), encrypted) } function clearCredentials() { @@ -162,6 +166,7 @@ async function syncNotes(credentials, pruneBefore) { } function createWindow() { + const appIndex = path.join(__dirname, '..', 'dist', 'index.html') const window = new BrowserWindow({ width: 1180, height: 780, @@ -187,14 +192,23 @@ function createWindow() { callback(false) }) - window.webContents.on('will-navigate', event => { - if (!isDev) event.preventDefault() + window.webContents.on('will-navigate', (event, url) => { + const allowedUrl = isDev ? 'http://127.0.0.1:5173/' : `file://${appIndex}` + if (url !== allowedUrl) event.preventDefault() + }) + + window.webContents.on('render-process-gone', (_event, details) => { + console.error('Renderer process gone:', details.reason, details.exitCode) + }) + + window.webContents.on('console-message', (_event, level, message, line, sourceId) => { + console.log(`[renderer:${level}] ${message} (${sourceId}:${line})`) }) if (isDev) { window.loadURL('http://127.0.0.1:5173') } else { - window.loadFile(path.join(__dirname, '..', 'dist', 'index.html')) + window.loadFile(appIndex) } } diff --git a/package-lock.json b/package-lock.json index b189682..78cafc4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nextcloud-notes-desktop", - "version": "0.1.2", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nextcloud-notes-desktop", - "version": "0.1.2", + "version": "0.1.3", "dependencies": { "react": "^19.2.6", "react-dom": "^19.2.6", diff --git a/package.json b/package.json index d8171ce..826cc22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nextcloud-notes-desktop", - "version": "0.1.2", + "version": "0.1.3", "private": true, "description": "Fast cross-platform desktop client for Nextcloud Notes", "author": { diff --git a/src/main.jsx b/src/main.jsx index a8cacb0..3b4608f 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -102,6 +102,37 @@ function Login({ onLogin }) { ) } +class ErrorBoundary extends React.Component { + constructor(props) { + super(props) + this.state = { error: null } + } + + static getDerivedStateFromError(error) { + return { error } + } + + componentDidCatch(error, errorInfo) { + console.error('Renderer error:', error, errorInfo) + } + + render() { + if (this.state.error) { + return ( + + + ! + Nextcloud Notes hit an error + The app did not start cleanly. This message replaces the blank screen so the issue can be diagnosed. + {this.state.error.message || String(this.state.error)} + + + ) + } + return this.props.children + } +} + function App() { const [account, setAccount] = React.useState(null) const [notes, setNotes] = React.useState([]) @@ -375,6 +406,8 @@ function App() { createRoot(document.getElementById('root')).render( - + + + )
The app did not start cleanly. This message replaces the blank screen so the issue can be diagnosed.