diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 12fcd78c3..6599091ab 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -93,9 +93,9 @@ "@umami/state": "workspace:^", "@umami/test-utils": "workspace:^", "@umami/tezos": "workspace:^", - "@umami/utils": "workspace:^", "@umami/typescript-config": "workspace:^", "@umami/tzkt": "workspace:^", + "@umami/utils": "workspace:^", "@vitejs/plugin-react": "^4.3.4", "babel-jest": "^29.7.0", "bignumber.js": "^9.1.2", @@ -151,11 +151,14 @@ "vite-plugin-checker": "^0.8.0", "vite-plugin-node-polyfills": "^0.17.0", "vite-plugin-sri": "^0.0.2", - "zod": "^3.23.8", - "@hookform/resolvers": "^3.9.1" + "zod": "^3.23.8" }, "packageManager": "pnpm@9.9.0", "dependencies": { - "electron-updater": "6.3.9" + "electron-log": "^5.2.4", + "electron-updater": "6.3.9", + "level": "^9.0.0", + "level-supports": "^6.0.0", + "level-transcoder": "^1.0.1" } } diff --git a/apps/desktop/public/electron.js b/apps/desktop/public/electron.js index 51a6ff25b..ba04d3db2 100644 --- a/apps/desktop/public/electron.js +++ b/apps/desktop/public/electron.js @@ -4,8 +4,13 @@ const path = require("path"); const url = require("url"); const process = require("process"); const { autoUpdater } = require("electron-updater"); +const { Level } = require("level"); +const log = require('electron-log'); +const fs = require('fs'); + const APP_PROTOCOL = "app"; const APP_HOST = "assets"; +// create in memory store of the leveldb database of previous version which had file:// protocol const appURL = app.isPackaged ? url.format({ @@ -26,6 +31,57 @@ protocol.registerSchemesAsPrivileged([ }, ]); +// Configure electron-log +log.transports.file.file = path.join(app.getPath('userData'), 'Local Storage', 'umami-desktop.log'); + +async function readAndCopyValues() { + // Path to the LevelDB database + const dbPath = path.join(app.getPath("userData"), "Local Storage", "leveldb"); + + // Check if the LevelDB database exists + if (!fs.existsSync(dbPath)) { + log.info("LevelDB database not found at path. Code:EM01", dbPath); + return; + } + // check if backup file exists + if (fs.existsSync(path.join(app.getPath("userData"), "Local Storage", "backup_leveldb.json"))) { + log.info("Backup file already exists. Code:EM02"); + return; + } + + // Open the LevelDB database + const db = new Level(dbPath, { valueEncoding: "utf-8" }); + await db.open(); + try { + const accountsValue = await db.get("_file://\x00\x01persist:accounts"); + let rootValue = await db.get("_file://\x00\x01persist:root"); + if ( !accountsValue || !rootValue) { + log.info("No data found in the database. Code:EM03"); + return; + } + console.log(accountsValue); + console.log(rootValue.length); + const storage = { + "persist:accounts": {accountsValue}, + "persist:root": {rootValue}, + }; + const rawBackup = JSON.stringify(storage); + try{ + fs.appendFileSync(path.join(app.getPath("userData"), "Local Storage", "backup_leveldb.json"), rawBackup); + } + catch(err){ + console.log("Error during leveldb backup creation Code:EM2.", err); + } + console.log("Migration done successfully"); +} + catch (err) { + log.error("Error during key migration Code:EM4.", err); + } finally { + db.close().catch((err) => { + log.error("Error closing the database. Code: EM5", err); + }); + } +} // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. let mainWindow; @@ -169,12 +225,13 @@ function start() { app.quit(); return; } + let waitForMigration = true; // Check for app updates, download and notify UI if update is available to be installed. try { autoUpdater.checkForUpdatesAndNotify(); } catch (e) { - console.log(e); + log.error(e); } if (!app.isDefaultProtocolClient("umami")) { @@ -223,7 +280,11 @@ function start() { // This method will be called when Electron has finished its initialization and // is ready to create the browser windows. // Some APIs can only be used after this event occurs. - app.whenReady().then(createWindow); + app.whenReady().then(async () => { + // Execute readAndCopyValues at the beginning + await readAndCopyValues(); + createWindow(); + }); app.on("activate", function () { // On macOS it's common to re-create a window in the app when the @@ -236,7 +297,7 @@ function start() { // Send event to UI when app update is ready to be installed. // If the update installation won't be triggered by the user, it will be applied the next time the app starts. autoUpdater.on("update-downloaded", event => { - console.log(`Umami update ${event.version} downloaded and ready to be installed`, url); + log.info(`Umami update ${event.version} downloaded and ready to be installed`, url); return mainWindow.webContents.send("app-update-downloaded"); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 97bb811e9..256289de2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,9 +33,21 @@ importers: apps/desktop: dependencies: + electron-log: + specifier: ^5.2.4 + version: 5.2.4 electron-updater: specifier: 6.3.9 version: 6.3.9 + level: + specifier: ^9.0.0 + version: 9.0.0 + level-supports: + specifier: ^6.0.0 + version: 6.0.0 + level-transcoder: + specifier: ^1.0.1 + version: 1.0.1 devDependencies: '@airgap/beacon-wallet': specifier: ^4.3.1 @@ -91,9 +103,6 @@ importers: '@emotion/styled': specifier: ^11.13.5 version: 11.13.5(@emotion/react@11.14.0(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(react@18.3.1) - '@hookform/resolvers': - specifier: ^3.9.1 - version: 3.9.1(react-hook-form@7.52.2(react@18.3.1)) '@reduxjs/toolkit': specifier: ^2.5.0 version: 2.5.0(react-redux@9.1.2(@types/react@18.3.12)(react@18.3.1)(redux@5.0.1))(react@18.3.1) @@ -243,7 +252,7 @@ importers: version: 33.2.0 electron-builder: specifier: ^25.1.8 - version: 25.1.8(electron-builder-squirrel-windows@24.13.3(dmg-builder@25.1.8)) + version: 25.1.8(electron-builder-squirrel-windows@24.13.3) electronmon: specifier: ^2.0.3 version: 2.0.3 @@ -6598,6 +6607,10 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + abstract-level@2.0.1: + resolution: {integrity: sha512-Btj350DnlLiEvcEli64YG2jwoCUdoYoxELcfJBIE6QC+1Gjk+IEuqlY2TWS5eoGa5W+fCwHu3+fLLDSdOmsklg==} + engines: {node: '>=16'} + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -7026,6 +7039,9 @@ packages: browser-assert@1.2.1: resolution: {integrity: sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==} + browser-level@2.0.0: + resolution: {integrity: sha512-RuYSCHG/jwFCrK+KWA3dLSUNLKHEgIYhO5ORPjJMjCt7T3e+RzpIDmYKWRHxq2pfKGXjlRuEff7y7RESAAgzew==} + browser-resolve@2.0.0: resolution: {integrity: sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==} @@ -7276,6 +7292,10 @@ packages: class-transformer@0.5.1: resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} + classic-level@2.0.0: + resolution: {integrity: sha512-ftiMvKgCQK+OppXcvMieDoYlYLYWhScK6yZRFBrrlHQRbm4k6Gr+yDgu/wt3V0k1/jtNbuiXAsRmuAFcD0Tx5Q==} + engines: {node: '>=18'} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -7963,6 +7983,10 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + electron-log@5.2.4: + resolution: {integrity: sha512-iX12WXc5XAaKeHg2QpiFjVwL+S1NVHPFd3V5RXtCmKhpAzXsVQnR3UEc0LovM6p6NkUQxDWnkdkaam9FNUVmCA==} + engines: {node: '>= 14'} + electron-publish@24.13.1: resolution: {integrity: sha512-2ZgdEqJ8e9D17Hwp5LEq5mLQPjqU3lv/IALvgp+4W8VeNhryfGhYEQC/PgDPMrnWUp+l60Ou5SJLsu+k4mhQ8A==} @@ -9063,6 +9087,10 @@ packages: is-buffer@1.1.6: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + is-buffer@2.0.5: + resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} + engines: {node: '>=4'} + is-bun-module@1.1.0: resolution: {integrity: sha512-4mTAVPlrXpaN3jtF0lsnPCMGnq4+qZjVIKq0HCpfcqf8OC1SM5oATCIAPM5V5FN05qp2NNnFndphmdZS9CV3hA==} @@ -9627,6 +9655,18 @@ packages: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} + level-supports@6.0.0: + resolution: {integrity: sha512-UU226PsfiFWLRPmuqgB3eADtvZM8WYv+aCnAl93B/2Ca+vgn9+b7o2boA7yOY2ri7Kk5Wk4aHxl3eNimpYZnxw==} + engines: {node: '>=16'} + + level-transcoder@1.0.1: + resolution: {integrity: sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==} + engines: {node: '>=12'} + + level@9.0.0: + resolution: {integrity: sha512-n+mVuf63mUEkd8NUx7gwxY+QF5vtkibv6fXTGUgtHWLPDaA5/XZjLcI/Q1nQ8k6OttHT6Ezt+7nSEXsRUfHtOQ==} + engines: {node: '>=18'} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -9875,6 +9915,10 @@ packages: resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} engines: {node: '>=10'} + maybe-combine-errors@1.0.0: + resolution: {integrity: sha512-eefp6IduNPT6fVdwPp+1NgD0PML1NU5P6j1Mj5nz1nidX8/sWY7119WL8vTAHgqfsY74TzW0w1XPgdYEKkGZ5A==} + engines: {node: '>=10'} + md5.js@1.3.5: resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} @@ -10108,6 +10152,10 @@ packages: engines: {node: '>=18'} hasBin: true + module-error@1.0.2: + resolution: {integrity: sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==} + engines: {node: '>=10'} + module-lookup-amd@9.0.2: resolution: {integrity: sha512-p7PzSVEWiW9fHRX9oM+V4aV5B2nCVddVNv4DZ/JB6t9GsXY4E+ZVhPpnwUX7bbJyGeeVZqhS8q/JZ/H77IqPFA==} engines: {node: '>=18'} @@ -10155,6 +10203,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-macros@2.2.2: + resolution: {integrity: sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -10224,6 +10275,10 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + node-gyp@9.4.1: resolution: {integrity: sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==} engines: {node: ^12.13 || ^14.13 || >=16} @@ -19409,6 +19464,15 @@ snapshots: dependencies: event-target-shim: 5.0.1 + abstract-level@2.0.1: + dependencies: + buffer: 6.0.3 + is-buffer: 2.0.5 + level-supports: 6.0.0 + level-transcoder: 1.0.1 + maybe-combine-errors: 1.0.0 + module-error: 1.0.2 + accepts@1.3.8: dependencies: mime-types: 2.1.35 @@ -19528,7 +19592,7 @@ snapshots: app-builder-bin@5.0.0-alpha.10: {} - app-builder-lib@24.13.3(dmg-builder@25.1.8(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@25.1.8)): + app-builder-lib@24.13.3(dmg-builder@25.1.8)(electron-builder-squirrel-windows@24.13.3): dependencies: '@develar/schema-utils': 2.6.5 '@electron/notarize': 2.2.1 @@ -19562,7 +19626,7 @@ snapshots: transitivePeerDependencies: - supports-color - app-builder-lib@25.1.8(dmg-builder@25.1.8(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@25.1.8)): + app-builder-lib@25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@24.13.3): dependencies: '@develar/schema-utils': 2.6.5 '@electron/notarize': 2.5.0 @@ -19980,6 +20044,10 @@ snapshots: browser-assert@1.2.1: {} + browser-level@2.0.0: + dependencies: + abstract-level: 2.0.1 + browser-resolve@2.0.0: dependencies: resolve: 1.22.8 @@ -20343,6 +20411,13 @@ snapshots: class-transformer@0.5.1: {} + classic-level@2.0.0: + dependencies: + abstract-level: 2.0.1 + module-error: 1.0.2 + napi-macros: 2.2.2 + node-gyp-build: 4.8.4 + classnames@2.5.1: {} clean-stack@2.2.0: {} @@ -20965,7 +21040,7 @@ snapshots: dmg-builder@25.1.8(electron-builder-squirrel-windows@24.13.3): dependencies: - app-builder-lib: 25.1.8(dmg-builder@25.1.8(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@25.1.8)) + app-builder-lib: 25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@24.13.3) builder-util: 25.1.7 builder-util-runtime: 9.2.10 fs-extra: 10.1.0 @@ -21062,7 +21137,7 @@ snapshots: electron-builder-squirrel-windows@24.13.3(dmg-builder@25.1.8): dependencies: - app-builder-lib: 24.13.3(dmg-builder@25.1.8(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@25.1.8)) + app-builder-lib: 24.13.3(dmg-builder@25.1.8)(electron-builder-squirrel-windows@24.13.3) archiver: 5.3.2 builder-util: 24.13.1 fs-extra: 10.1.0 @@ -21070,9 +21145,9 @@ snapshots: - dmg-builder - supports-color - electron-builder@25.1.8(electron-builder-squirrel-windows@24.13.3(dmg-builder@25.1.8)): + electron-builder@25.1.8(electron-builder-squirrel-windows@24.13.3): dependencies: - app-builder-lib: 25.1.8(dmg-builder@25.1.8(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@25.1.8)) + app-builder-lib: 25.1.8(dmg-builder@25.1.8)(electron-builder-squirrel-windows@24.13.3) builder-util: 25.1.7 builder-util-runtime: 9.2.10 chalk: 4.1.2 @@ -21087,6 +21162,8 @@ snapshots: - electron-builder-squirrel-windows - supports-color + electron-log@5.2.4: {} + electron-publish@24.13.1: dependencies: '@types/fs-extra': 9.0.13 @@ -21393,7 +21470,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.17.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.17.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -21446,7 +21523,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.17.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.17.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -22470,6 +22547,8 @@ snapshots: is-buffer@1.1.6: {} + is-buffer@2.0.5: {} + is-bun-module@1.1.0: dependencies: semver: 7.6.3 @@ -23225,6 +23304,19 @@ snapshots: dependencies: readable-stream: 2.3.8 + level-supports@6.0.0: {} + + level-transcoder@1.0.1: + dependencies: + buffer: 6.0.3 + module-error: 1.0.2 + + level@9.0.0: + dependencies: + abstract-level: 2.0.1 + browser-level: 2.0.0 + classic-level: 2.0.0 + leven@3.1.0: {} levn@0.4.1: @@ -23484,6 +23576,8 @@ snapshots: escape-string-regexp: 4.0.0 optional: true + maybe-combine-errors@1.0.0: {} + md5.js@1.3.5: dependencies: hash-base: 3.1.0 @@ -23813,6 +23907,8 @@ snapshots: ast-module-types: 6.0.0 node-source-walk: 7.0.0 + module-error@1.0.2: {} + module-lookup-amd@9.0.2: dependencies: commander: 12.1.0 @@ -23862,6 +23958,8 @@ snapshots: nanoid@3.3.7: {} + napi-macros@2.2.2: {} + natural-compare@1.4.0: {} negotiator@0.6.3: {} @@ -23920,6 +24018,8 @@ snapshots: node-forge@1.3.1: {} + node-gyp-build@4.8.4: {} + node-gyp@9.4.1: dependencies: env-paths: 2.2.1