diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 60a44906..43780313 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -10,4 +10,4 @@ liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry -custom: [paypal.me/antongithub, antonreshetov.gumroad.com/l/masscode] +custom: [paypal.me/antongithub, antonreshetov.gumroad.com/l/masscode, https://buy.polar.sh/polar_cl_bpDmjg079kfiAVtdtrtBwxyRXN6NK8B4Bvqdk2QXdx7] diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml deleted file mode 100644 index e0f08086..00000000 --- a/.github/workflows/build-and-release.yml +++ /dev/null @@ -1,178 +0,0 @@ -name: Build and Release - -on: - push: - tags: - - 'v*' - workflow_dispatch: # Allow manual trigger - inputs: - tag: - description: 'Tag for release (e.g., v1.0.0)' - required: true - default: v4.0.0 - -jobs: - build: - name: Build for ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - - os: macos-latest - platform: mac - arch: x64,arm64 - - os: windows-latest - platform: win - arch: x64 - - os: ubuntu-latest - platform: linux - arch: x64 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: latest - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20.16.0 # Project's Node version - cache: pnpm - - - name: Install dependencies - run: pnpm install - - - name: Rebuild native dependencies - run: pnpm run rebuild - - - name: Build application - run: pnpm run build:${{ matrix.platform }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: masscode-${{ matrix.platform }}-${{ github.ref_name || inputs.tag }} - path: | - dist/*.dmg - dist/*.pkg - dist/*.exe - dist/*.msi - dist/*.AppImage - dist/*.snap - !dist/*-sponsored.* - !dist/*.yml - !dist/*.blockmap - if-no-files-found: warn - retention-days: 30 - - build-sponsored: - name: Build Sponsored for ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - - os: macos-latest - platform: mac - arch: x64,arm64 - - os: windows-latest - platform: win - arch: x64 - - os: ubuntu-latest - platform: linux - arch: x64 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: latest - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: 20.16.0 # Project's Node version - cache: pnpm - - - name: Install dependencies - run: pnpm install - - - name: Rebuild native dependencies - run: pnpm run rebuild - - - name: Build application - run: pnpm run build:sponsored:${{ matrix.platform }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VITE_SPONSORED: true - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: sponsored-${{ matrix.platform }}-${{ github.ref_name || inputs.tag }} - path: | - dist/*.dmg - dist/*.pkg - dist/*.exe - dist/*.msi - dist/*.AppImage - dist/*.snap - !dist/*.yml - !dist/*.blockmap - if-no-files-found: warn - retention-days: 30 - - release: - name: Create Release - needs: build - runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Download artifacts from "build" job - uses: actions/download-artifact@v4 - with: - pattern: masscode-* - path: artifacts - - - name: Display structure of downloaded files - run: ls -lR artifacts/ - - - name: Prepare release files - run: | - mkdir -p release-files - find artifacts/masscode-* -type f \( -name "massCode-*.dmg" -o -name "massCode-*.pkg" -o -name "massCode-*.exe" -o -name "massCode-*.msi" -o -name "massCode-*.AppImage" -o -name "massCode-*.snap" \) ! -name "*-sponsored.*" -exec cp {} release-files/ \; - echo "Files prepared for release:" - ls -lh release-files/ - - - name: Get package version - id: package-version - run: | - echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT - - - name: Create Release - id: create_release - uses: softprops/action-gh-release@v2 - with: - files: release-files/* - tag_name: ${{ github.ref_name || inputs.tag }} - draft: true - generate_release_notes: true - append_body: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/build-sponsored.yml b/.github/workflows/build-sponsored.yml new file mode 100644 index 00000000..d0bb55bf --- /dev/null +++ b/.github/workflows/build-sponsored.yml @@ -0,0 +1,63 @@ +name: Build Sponsored + +on: + workflow_dispatch: + +jobs: + build-sponsored: + name: Build Sponsored for ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: macos-latest + platform: mac + - os: windows-latest + platform: win + - os: ubuntu-latest + platform: linux + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: latest + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.16.0 + cache: pnpm + + - name: Install dependencies + run: pnpm install + + - name: Rebuild native dependencies + run: pnpm run rebuild + + - name: Build application (sponsored) + run: pnpm run build:sponsored:${{ matrix.platform }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VITE_SPONSORED: true + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: sponsored-${{ matrix.platform }}-${{ github.ref_name }} + path: | + dist/*.dmg + dist/*.pkg + dist/*.exe + dist/*.msi + dist/*.AppImage + dist/*.snap + if-no-files-found: warn + retention-days: 30 + + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..3b6e3e58 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,106 @@ +name: Release + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + tag: + description: 'Tag for release (e.g., v1.0.0)' + required: true + default: v4.0.0 + +jobs: + build: + name: Build for ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: macos-latest + platform: mac + - os: windows-latest + platform: win + - os: ubuntu-latest + platform: linux + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: latest + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.16.0 + cache: pnpm + + - name: Install dependencies + run: pnpm install + + - name: Rebuild native dependencies + run: pnpm run rebuild + + - name: Build application + run: pnpm run build:${{ matrix.platform }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: masscode-${{ matrix.platform }}-${{ github.ref_name || inputs.tag }} + path: | + dist/*.dmg + dist/*.pkg + dist/*.exe + dist/*.msi + dist/*.AppImage + dist/*.snap + !dist/*-sponsored.* + !dist/*.yml + !dist/*.blockmap + if-no-files-found: warn + retention-days: 30 + + release: + name: Create Release + needs: build + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download artifacts from "build" job + uses: actions/download-artifact@v4 + with: + pattern: masscode-* + path: artifacts + + - name: Generate changelog + run: npx changelogithub --output release-notes.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create Release + id: create_release + uses: softprops/action-gh-release@v2 + with: + files: artifacts/**/* + tag_name: ${{ github.ref_name || inputs.tag }} + draft: true + body_path: release-notes.md + generate_release_notes: true + append_body: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + diff --git a/CHANGELOG.md b/CHANGELOG.md index 12f3c400..69af02bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +# [4.2.0](https://github.com/massCodeIO/massCode/compare/v4.1.0...v4.2.0) (2025-10-08) + + +### Bug Fixes + +* **editor:** prevent header and editor display for multiple selected snippets ([e1d4ccd](https://github.com/massCodeIO/massCode/commit/e1d4ccd995f5d1ea14f50d9d8bef51101ffb4bb1)) +* **editor:** show code preview panel ([5e91b74](https://github.com/massCodeIO/massCode/commit/5e91b74c93a57b491bf4b84241e8b2ff664551dd)) +* **i18n:** update sidebar toggle translations ([f819f4a](https://github.com/massCodeIO/massCode/commit/f819f4acd83f90387e8644b88e871f5451b17d40)) +* **scrollbar:** suppress horizontal scrolling ([53f6aef](https://github.com/massCodeIO/massCode/commit/53f6aef8497be9aad13b680d801a7bbcd8312198)) +* **snippets:** use default folder language for fragments [#611](https://github.com/massCodeIO/massCode/issues/611) ([#612](https://github.com/massCodeIO/massCode/issues/612)) ([4c52a5e](https://github.com/massCodeIO/massCode/commit/4c52a5e4a6c607dbb8009dd1c660f964a474e3a0)) +* update entitlements and enable hardened runtime for macOS builds ([d350977](https://github.com/massCodeIO/massCode/commit/d350977b02c158789b887f7cf54981310c738bd4)) + + +### Features + +* add show/hide sidebar toggle ([#610](https://github.com/massCodeIO/massCode/issues/610)) ([64cc14f](https://github.com/massCodeIO/massCode/commit/64cc14f803ed27490c8cfe087ccb3c3d9fd523ee)) + + + # [4.1.0](https://github.com/massCodeIO/massCode/compare/v4.0.4...v4.1.0) (2025-10-03) diff --git a/README.md b/README.md index 65d423e9..a349c6db 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,8 @@ You can support massCode through the following channels: [![Donate via Open Collective](https://img.shields.io/badge/donate-Open%20Collective-blue.svg?style=popout&logo=opencollective)](https://opencollective.com/masscode) [![Donate via PayPal](https://img.shields.io/badge/donate-PayPal-blue.svg?style=popout&logo=paypal)](https://paypal.me/antongithub) -[![Donate via Ko-Fi](https://img.shields.io/badge/donate-Gumroad-blue?style=popout&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzQiIGhlaWdodD0iMzMiIHZpZXdCb3g9IjAgMCAzNCAzMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGVsbGlwc2UgY3g9IjE5LjgyODciIGN5PSIxOS4xMzU5IiByeD0iMTQuMTcxNCIgcnk9IjEzLjY3NjUiIGZpbGw9ImJsYWNrIi8+CjxwYXRoIGQ9Ik0xNi4xNzE0IDI5Ljk0NjRDMjQuNDAzMiAyOS45NDY0IDMxLjEyNDEgMjMuNDk5NSAzMS4xMjQxIDE1LjQ4ODdDMzEuMTI0MSA3LjQ3OCAyNC40MDMyIDEuMDMxMDEgMTYuMTcxNCAxLjAzMTAxQzcuOTM5NyAxLjAzMTAxIDEuMjE4NzUgNy40NzggMS4yMTg3NSAxNS40ODg3QzEuMjE4NzUgMjMuNDk5NSA3LjkzOTcgMjkuOTQ2NCAxNi4xNzE0IDI5Ljk0NjRaIiBmaWxsPSIjRkY5MEU4IiBzdHJva2U9ImJsYWNrIiBzdHJva2Utd2lkdGg9IjEuNTYyNSIvPgo8cGF0aCBkPSJNMTUuMDQ2NyAyMi43ODI3QzEwLjg2MiAyMi43ODI3IDguNDAwMzkgMTkuNDAyNCA4LjQwMDM5IDE1LjE5NzZDOC40MDAzOSAxMC44Mjc5IDExLjEwODEgNy4yODI3MSAxNi4yNzc0IDcuMjgyNzFDMjEuNjEwOSA3LjI4MjcxIDIzLjQxNiAxMC45MTA0IDIzLjQ5ODEgMTIuOTcxNUgxOS42NDE2QzE5LjU1OTYgMTEuODE3MyAxOC41NzQ5IDEwLjA4NTkgMTYuMTk1NCAxMC4wODU5QzEzLjY1MTggMTAuMDg1OSAxMi4wMTA3IDEyLjMxMiAxMi4wMTA3IDE1LjAzMjdDMTIuMDEwNyAxNy43NTM1IDEzLjY1MTggMTkuOTc5NSAxNi4xOTU0IDE5Ljk3OTVDMTguNDkyOSAxOS45Nzk1IDE5LjQ3NzUgMTguMTY1NyAxOS44ODc4IDE2LjM1MTlIMTYuMTk1NFYxNC44Njc4SDIzLjk0MzJWMjIuNDUyOUgyMC41NDQyVjE3LjY3MUMyMC4yOTggMTkuNDAyNCAxOS4yMzEzIDIyLjc4MjcgMTUuMDQ2NyAyMi43ODI3WiIgZmlsbD0iYmxhY2siLz4KPC9zdmc+Cg==)](https://antonreshetov.gumroad.com/l/masscode) +[![Donate via Gummroad](https://img.shields.io/badge/donate-Gumroad-blue?style=popout&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzQiIGhlaWdodD0iMzMiIHZpZXdCb3g9IjAgMCAzNCAzMyIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGVsbGlwc2UgY3g9IjE5LjgyODciIGN5PSIxOS4xMzU5IiByeD0iMTQuMTcxNCIgcnk9IjEzLjY3NjUiIGZpbGw9ImJsYWNrIi8+CjxwYXRoIGQ9Ik0xNi4xNzE0IDI5Ljk0NjRDMjQuNDAzMiAyOS45NDY0IDMxLjEyNDEgMjMuNDk5NSAzMS4xMjQxIDE1LjQ4ODdDMzEuMTI0MSA3LjQ3OCAyNC40MDMyIDEuMDMxMDEgMTYuMTcxNCAxLjAzMTAxQzcuOTM5NyAxLjAzMTAxIDEuMjE4NzUgNy40NzggMS4yMTg3NSAxNS40ODg3QzEuMjE4NzUgMjMuNDk5NSA3LjkzOTcgMjkuOTQ2NCAxNi4xNzE0IDI5Ljk0NjRaIiBmaWxsPSIjRkY5MEU4IiBzdHJva2U9ImJsYWNrIiBzdHJva2Utd2lkdGg9IjEuNTYyNSIvPgo8cGF0aCBkPSJNMTUuMDQ2NyAyMi43ODI3QzEwLjg2MiAyMi43ODI3IDguNDAwMzkgMTkuNDAyNCA4LjQwMDM5IDE1LjE5NzZDOC40MDAzOSAxMC44Mjc5IDExLjEwODEgNy4yODI3MSAxNi4yNzc0IDcuMjgyNzFDMjEuNjEwOSA3LjI4MjcxIDIzLjQxNiAxMC45MTA0IDIzLjQ5ODEgMTIuOTcxNUgxOS42NDE2QzE5LjU1OTYgMTEuODE3MyAxOC41NzQ5IDEwLjA4NTkgMTYuMTk1NCAxMC4wODU5QzEzLjY1MTggMTAuMDg1OSAxMi4wMTA3IDEyLjMxMiAxMi4wMTA3IDE1LjAzMjdDMTIuMDEwNyAxNy43NTM1IDEzLjY1MTggMTkuOTc5NSAxNi4xOTU0IDE5Ljk3OTVDMTguNDkyOSAxOS45Nzk1IDE5LjQ3NzUgMTguMTY1NyAxOS44ODc4IDE2LjM1MTlIMTYuMTk1NFYxNC44Njc4SDIzLjk0MzJWMjIuNDUyOUgyMC41NDQyVjE3LjY3MUMyMC4yOTggMTkuNDAyNCAxOS4yMzEzIDIyLjc4MjcgMTUuMDQ2NyAyMi43ODI3WiIgZmlsbD0iYmxhY2siLz4KPC9zdmc+Cg==)](https://antonreshetov.gumroad.com/l/masscode) +[![Donate via Polar](https://img.shields.io/badge/donate-Polar-blue?style=popout&logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjMwMCIgdmlld0JveD0iMCAwIDMwMCAzMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8xXzEwKSI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNjYuNDI4NCAyNzQuMjZDMTM0Ljg3NiAzMjAuNTkzIDIyNy45MjUgMzAyLjY2NiAyNzQuMjU4IDIzNC4yMTlDMzIwLjU5MyAxNjUuNzcxIDMwMi42NjYgNzIuNzIyMiAyMzQuMjE4IDI2LjM4ODVDMTY1Ljc3IC0xOS45NDUxIDcyLjcyMSAtMi4wMTgxIDI2LjM4NzIgNjYuNDI5N0MtMTkuOTQ2NSAxMzQuODc3IC0yLjAxOTM5IDIyNy45MjcgNjYuNDI4NCAyNzQuMjZaTTQ3Ljk1NTUgMTE2LjY3QzMwLjgzNzQgMTY5LjI2MyAzNi41NDQ1IDIyMS44OTMgNTkuMjQ1NCAyNTYuMzczQzE4LjA0MTIgMjE3LjM2MSA3LjI3NTYyIDE1MC4zMDcgMzYuOTQzNiA5Mi4zMThDNTUuOTE1MSA1NS4yMzYyIDg3LjU2NjQgMjkuMzkzNyAxMjIuNSAxOC4zNDgzQzkwLjU5MTEgMzYuNzEwNSA2Mi41NTQ5IDcxLjgxNDQgNDcuOTU1NSAxMTYuNjdaTTE3NS4zNDcgMjgzLjEzN0MyMTEuMzc3IDI3Mi42MDYgMjQ0LjIxMSAyNDYuMzg1IDI2My42ODUgMjA4LjMyMkMyOTMuMTAxIDE1MC44MjUgMjgyLjc2OCA4NC40MTcyIDI0Mi40MjcgNDUuMjY3M0MyNjQuMjIgNzkuNzYyNiAyNjkuNDczIDEzMS41NDIgMjUyLjYzMSAxODMuMjg3QzIzNy42MTUgMjI5LjQyMSAyMDguMzg1IDI2NS4yMzkgMTc1LjM0NyAyODMuMTM3Wk0xODMuNjI3IDI2Ni4yMjlDMjA3Ljk0NSAyNDUuNDE4IDIyOC4wMTYgMjEwLjYwNCAyMzYuOTM1IDE2OC43OUMyNTEuMDMzIDEwMi42OTMgMjMyLjU1MSA0MS4xOTc4IDE5NS4xMTIgMjAuNjc2OEMyMTQuOTcgNDcuMzk0NSAyMjUuMDIyIDk5LjI5MDIgMjE4LjgyNCAxNTcuMzMzQzIxNC4wODUgMjAxLjcyNCAyMDAuODE0IDI0MC41OTMgMTgzLjYyNyAyNjYuMjI5Wk02My43MTc3IDEzMS44NDRDNDkuNTE1NSAxOTguNDMgNjguMzc3IDI2MC4zNDUgMTA2LjM3NCAyODAuNDA1Qzg1Ljk5NjIgMjU0LjAwOSA3NS41OTY4IDIwMS41MTQgODEuODc1OCAxNDIuNzExQzg2LjUzNzQgOTkuMDUzNiA5OS40NTAzIDYwLjczNyAxMTYuMjI1IDM1LjA5NjlDOTIuMjY3NyA1NS45ODMgNzIuNTM4NCA5MC40ODkyIDYzLjcxNzcgMTMxLjg0NFpNMTk5LjgzNCAxNDkuNTYxQzIwMC45MDggMjE3LjQ3MyAxNzkuNTkgMjcyLjg3OCAxNTIuMjIyIDI3My4zMDlDMTI0Ljg1MyAyNzMuNzQyIDEwMS43OTcgMjE5LjAzOSAxMDAuNzI0IDE1MS4xMjdDOTkuNjUxMSA4My4yMTM4IDEyMC45NjggMjcuODA5NCAxNDguMzM3IDI3LjM3N0MxNzUuNzA1IDI2Ljk0NDYgMTk4Ljc2MiA4MS42NDggMTk5LjgzNCAxNDkuNTYxWiIgZmlsbD0id2hpdGUiLz4KPC9nPgo8ZGVmcz4KPGNsaXBQYXRoIGlkPSJjbGlwMF8xXzEwIj4KPHJlY3Qgd2lkdGg9IjMwMCIgaGVpZ2h0PSIzMDAiIGZpbGw9IndoaXRlIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg==)](https://buy.polar.sh/polar_cl_bpDmjg079kfiAVtdtrtBwxyRXN6NK8B4Bvqdk2QXdx7) diff --git a/src/main/db/index.ts b/src/main/db/index.ts index 25347c8f..488fb4ff 100644 --- a/src/main/db/index.ts +++ b/src/main/db/index.ts @@ -5,6 +5,7 @@ import Database from 'better-sqlite3' import { format } from 'date-fns' import fs from 'fs-extra' import { store } from '../store' +import { log } from '../utils' const DB_NAME = 'massCode.db' const isDev = process.env.NODE_ENV === 'development' @@ -136,7 +137,7 @@ export function useDB() { return db } catch (error) { - console.error('Database initialization failed:', error) + log('Database initialization failed', error) throw error } } @@ -167,7 +168,7 @@ export function reloadDB() { console.log(`Database successfully reloaded: ${dbPath}`) } catch (error) { - console.error('Error while reloading the database:', error) + log('Error while reloading the database', error) throw error } } @@ -201,7 +202,7 @@ export function clearDB() { stmt() } catch (error) { - console.error('Error while clearing the database:', error) + log('Error while clearing the database', error) throw error } } @@ -228,7 +229,7 @@ export async function moveDB(path: string) { reloadDB() } catch (error) { - console.error('Error while moving the database:', error) + log('Error while moving the database', error) throw error } } @@ -256,7 +257,7 @@ export async function createBackup(manual = false) { return backupFilePath } catch (error) { - console.error('Error creating database backup:', error) + log('Error creating database backup', error) throw error } } @@ -338,12 +339,12 @@ export async function startAutoBackup() { } } catch (error) { - console.error('Error during scheduled backup:', error) + log('Error during scheduled backup', error) } }, intervalMs) } catch (error) { - console.error('Error starting auto backup:', error) + log('Error starting auto backup', error) } } @@ -377,7 +378,7 @@ export async function restoreFromBackup(backupFilePath: string) { console.warn(`Database restored from backup: ${backupFilePath}`) } catch (error) { - console.error('Error restoring database from backup:', error) + log('Error restoring database from backup', error) throw error } } @@ -415,7 +416,7 @@ export async function getBackupList() { ) } catch (error) { - console.error('Error getting backup list:', error) + log('Error getting backup list', error) return [] } } @@ -454,7 +455,7 @@ export async function moveBackupStorage(newPath: string) { store.preferences.set('backup.path', newPath) } catch (error) { - console.error('Error while moving backup storage:', error) + log('Error while moving backup storage', error) throw error } } diff --git a/src/main/index.ts b/src/main/index.ts index 0aabe5db..1b341d41 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -9,6 +9,7 @@ import { registerIPC } from './ipc' import { mainMenu } from './menu/main' import { store } from './store' import { checkForUpdates } from './updates' +import { log } from './utils' process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true' // Отключаем security warnings @@ -73,12 +74,41 @@ if (!gotTheLock) { app.quit() } else { - app.whenReady().then(() => { - createWindow() - registerIPC() - initApi() - checkForUpdates() - startAutoBackup() + app.whenReady().then(async () => { + try { + createWindow() + } + catch (error) { + log('Error creating window', error) + } + + try { + registerIPC() + } + catch (error) { + log('Error registering IPC', error) + } + + try { + initApi() + } + catch (error) { + log('Error initializing API', error) + } + + try { + checkForUpdates() + } + catch (error) { + log('Error checking for updates', error) + } + + try { + await startAutoBackup() + } + catch (error) { + log('Error starting auto backup', error) + } if (store.app.get('isAutoMigratedFromJson')) { return @@ -92,7 +122,7 @@ else { store.app.set('isAutoMigratedFromJson', true) } catch (err) { - console.error('Error on auto migration JSON to SQLite:', err) + log('Error on auto migration JSON to SQLite', err) } }) @@ -126,4 +156,22 @@ else { app.on('open-url', (_, url) => { BrowserWindow.getFocusedWindow()?.webContents.send('system:deep-link', url) }) + + // Global error handlers + process.on('uncaughtException', (err) => { + BrowserWindow.getFocusedWindow()?.webContents.send('system:error', { + source: 'main', + message: err.message, + stack: err.stack, + }) + }) + + process.on('unhandledRejection', (reason) => { + const err = reason instanceof Error ? reason : new Error(String(reason)) + BrowserWindow.getFocusedWindow()?.webContents.send('system:error', { + source: 'main', + message: err.message, + stack: err.stack, + }) + }) } diff --git a/src/main/types/ipc.ts b/src/main/types/ipc.ts index 75d6c39a..231aa067 100644 --- a/src/main/types/ipc.ts +++ b/src/main/types/ipc.ts @@ -41,6 +41,7 @@ type SystemAction = | 'open-external' | 'deep-link' | 'update-available' + | 'error' type PrettierAction = 'format' type FsAction = 'assets' diff --git a/src/main/utils/index.ts b/src/main/utils/index.ts new file mode 100644 index 00000000..192f20fc --- /dev/null +++ b/src/main/utils/index.ts @@ -0,0 +1,14 @@ +import { BrowserWindow } from 'electron' + +export function log(context: string, error: unknown): void { + const message = error instanceof Error ? error.message : String(error) + const stack = error instanceof Error ? error.stack : undefined + + console.error(`[${context}] ${message}`, error) + + BrowserWindow.getFocusedWindow()?.webContents.send('system:error', { + context, + message, + stack, + }) +} diff --git a/src/renderer/ipc/listeners/system.ts b/src/renderer/ipc/listeners/system.ts index 7e665cab..361733ca 100644 --- a/src/renderer/ipc/listeners/system.ts +++ b/src/renderer/ipc/listeners/system.ts @@ -48,4 +48,8 @@ export function registerSystemListeners() { }, }) }) + + ipc.on('system:error', (_, payload) => { + console.error(`[system][${payload.context}]`, payload) + }) }