From f999969c1350f8aff00947445ce160c19ed34893 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Sun, 29 Jan 2023 16:07:26 +1100 Subject: [PATCH] chore!: store config in electron-defined userData folder instead of home folder - cli can no longer detect where config will be, so config-related cli prompts have been removed - should avoid file conflicts and enable portable builds - users can export their data in the more readable .json format from the profiles section of the menu and no longer require direct access to the config file --- bin.mjs | 28 +------- scripts/enhance-desktop-app.mjs | 19 +----- src/api/electron.cjs | 110 ++++++++++++++++++-------------- src/worker.js | 7 +- 4 files changed, 74 insertions(+), 90 deletions(-) diff --git a/bin.mjs b/bin.mjs index afe5e74..d2d3981 100755 --- a/bin.mjs +++ b/bin.mjs @@ -13,14 +13,12 @@ import { createRequire } from "node:module"; import { getAppPath, getBackupPath, - getConfigPath, checkEnhancementVersion, setNotionPath, unpackApp, applyEnhancements, takeBackup, restoreBackup, - removeConfig, } from "./scripts/enhance-desktop-app.mjs"; import { existsSync } from "node:fs"; const nodeRequire = createRequire(import.meta.url), @@ -218,7 +216,6 @@ try { const appPath = getAppPath(), backupPath = getBackupPath(), - configPath = getConfigPath(), insertVersion = checkEnhancementVersion(); const messages = { @@ -239,10 +236,6 @@ try { "manual-removal-instructions": `to remove the notion-enhancer from notion, uninstall notion and then install a vanilla version of the app from https://www.notion.so/desktop (mac, windows) or ${manifest.homepage}/getting-started/installation (linux)`, - - "config-found": `config found`, - "config-not-found": `config not found: nothing to remove`, - "prompt-config-removal": `remove?`, }; const SUCCESS = chalk`{bold.whiteBright SUCCESS} {green ✔}`, FAILURE = chalk`{bold.whiteBright FAILURE} {red ✘}`, @@ -316,9 +309,8 @@ try { stopSpinner(); print` {grey * ${messages["version-applied"]}}\n`; return SUCCESS; - }; - - const interactiveRemoveEnhancements = async () => { + }, + interactiveRemoveEnhancements = async () => { if (!appPath) { // notion not installed print` {red * ${messages["notion-not-found"]}}\n`; @@ -331,19 +323,6 @@ try { } print` {grey * ${messages["notion-found"]}: ${messages["not-applied"]}}\n`; return SUCCESS; - }, - promptConfigRemoval = async () => { - if (existsSync(configPath)) { - print` {grey * ${messages["config-found"]}: ${configPath}}\n`; - // prettier-ignore - const promptRemoval = await promptConfirmation(messages["prompt-config-removal"]); - if (["Y", "y"].includes(promptRemoval)) { - print` `; - startSpinner(); - await removeConfig(); - stopSpinner(); - } else print`\n`; - } else print` {grey * ${messages["config-not-found"]}}\n`; }; switch (args["_"][0]) { @@ -357,7 +336,6 @@ try { case "remove": { print`{bold.whiteBright [NOTION-ENHANCER] REMOVE}\n`; const res = await interactiveRemoveEnhancements(); - await promptConfigRemoval(); print`${res}\n`; break; } @@ -366,8 +344,6 @@ try { printObject({ appPath, backupPath, - configPath, - configExists: existsSync(configPath), insertVersion, currentVersion: manifest.version, }); diff --git a/scripts/enhance-desktop-app.mjs b/scripts/enhance-desktop-app.mjs index b7f784f..a797d05 100755 --- a/scripts/enhance-desktop-app.mjs +++ b/scripts/enhance-desktop-app.mjs @@ -15,7 +15,7 @@ import { createRequire } from "node:module"; import patch from "./patch-desktop-app.mjs"; -let __notionResources, __enhancerConfig; +let __notionResources; const nodeRequire = createRequire(import.meta.url), manifest = nodeRequire("../package.json"), platform = @@ -92,12 +92,6 @@ const setNotionPath = (path) => { getAppPath = () => ["app", "app.asar"].map(getResourcePath).find(existsSync), getBackupPath = () => ["app.bak", "app.asar.bak"].map(getResourcePath).find(existsSync), - getConfigPath = () => { - if (__enhancerConfig) return __enhancerConfig; - const home = platform === "wsl" ? polyfillWslEnv("HOMEPATH") : os.homedir(); - __enhancerConfig = resolve(`${home}/.notion-enhancer.db`); - return __enhancerConfig; - }, checkEnhancementVersion = () => { // prettier-ignore const manifestPath = getResourcePath("app/node_modules/notion-enhancer/package.json"); @@ -125,8 +119,8 @@ const unpackApp = async () => { // call patch-desktop-app.mjs on each file // prettier-ignore const notionScripts = (await readdirDeep(appPath)) - .filter((file) => file.endsWith(".js")), - scriptUpdates = []; + .filter((file) => file.endsWith(".js")), + scriptUpdates = []; for (const file of notionScripts) { const scriptId = file.slice(appPath.length + 1, -3).replace(/\\/g, "/"), scriptContent = await fsp.readFile(file, { encoding: "utf8" }), @@ -170,23 +164,16 @@ const unpackApp = async () => { const appPath = getAppPath(); if (destPath !== appPath) await fsp.rm(appPath, { recursive: true }); return true; - }, - removeConfig = async () => { - if (!existsSync(getConfigPath())) return; - await fsp.rm(getConfigPath()); - return true; }; export { getResourcePath, getAppPath, getBackupPath, - getConfigPath, checkEnhancementVersion, setNotionPath, unpackApp, applyEnhancements, takeBackup, restoreBackup, - removeConfig, }; diff --git a/src/api/electron.cjs b/src/api/electron.cjs index 1be69ca..be38e83 100644 --- a/src/api/electron.cjs +++ b/src/api/electron.cjs @@ -48,80 +48,96 @@ const sendMessage = (channel, message) => { ipcRenderer.on(channel, listener); }; -let __db; +let __db, __statements, __transactions; const initDatabase = (namespace, fallbacks = {}) => { if (Array.isArray(namespace)) namespace = namespace.join("__"); namespace = namespace ? namespace + "__" : ""; const namespaceify = (key) => key.startsWith(namespace) ? key : namespace + key; - // schema: - // - ("profileIds") = $profileId[] - // - ("activeProfile") -> $profileId - // - $profileId: ("profileName") -> string - // - $profileId__enabledMods: ($modId) -> boolean - // - $profileId__$modId: ($optionKey) -> value + __db ??= (async () => { + const { app, ipcRenderer } = require("electron"), + isRenderer = process?.type === "renderer", + userData = isRenderer + ? await ipcRenderer.invoke("notion-enhancer", "get-user-data-folder") + : app.getPath("userData"); - const table = "settings", - sqlite = require("better-sqlite3"), - db = __db ?? sqlite(path.resolve(`${os.homedir()}/.notion-enhancer.db`)), - init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} ( - key TEXT PRIMARY KEY, - value TEXT - )`); - init.run(); - __db = db; + const table = "settings", + sqlite = require("better-sqlite3"), + db = sqlite(path.resolve(`${userData}/notion-enhancer.db`)), + init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} ( + key TEXT PRIMARY KEY, + value TEXT + )`); + init.run(); - const insert = db.prepare(`INSERT INTO ${table} (key, value) VALUES (?, ?)`), - update = db.prepare(`UPDATE ${table} SET value = ? WHERE key = ?`), - select = db.prepare(`SELECT * FROM ${table} WHERE key = ? LIMIT 1`), - remove = db.prepare(`DELETE FROM ${table} WHERE key = ?`), - removeMany = db.transaction((arr) => arr.forEach((key) => remove.run(key))), - dump = db.prepare(`SELECT * FROM ${table}`), - populate = db.transaction((obj) => { - for (const key in obj) { - if (select.get(key)) update.run(obj[key], key); - else insert.run(key, obj[key]); - } - }); + // schema: + // - ("profileIds") = $profileId[] + // - ("activeProfile") -> $profileId + // - $profileId: ("profileName") -> string + // - $profileId__enabledMods: ($modId) -> boolean + // - $profileId__$modId: ($optionKey) -> value + __statements = { + insert: db.prepare(`INSERT INTO ${table} (key, value) VALUES (?, ?)`), + update: db.prepare(`UPDATE ${table} SET value = ? WHERE key = ?`), + select: db.prepare(`SELECT * FROM ${table} WHERE key = ? LIMIT 1`), + delete: db.prepare(`DELETE FROM ${table} WHERE key = ?`), + dump: db.prepare(`SELECT * FROM ${table}`), + }; + __transactions = { + remove: db.transaction((arr) => { + arr.forEach((key) => __statements.delete.run(key)); + }), + set: db.transaction((obj) => { + for (const key in obj) { + if (__statements.select.get(key) === undefined) { + __statements.insert.run(key, obj[key]); + } else __statements.update.run(obj[key], key); + } + }), + }; + return db; + })(); return { - // wrap methods in promises for consistency w/ chrome.storage - get: (key) => { + get: async (key) => { + await __db; const fallback = fallbacks[key]; key = namespaceify(key); try { - const value = JSON.parse(select.get(key)?.value); - return Promise.resolve(value ?? fallback); + const value = JSON.parse(__statements.select.get(key)?.value); + return value ?? fallback; } catch {} - return Promise.resolve(fallback); + return fallback; }, - set: (key, value) => { + set: async (key, value) => { + await __db; key = namespaceify(key); value = JSON.stringify(value); - if (select.get(key) === undefined) { - insert.run(key, value); - } else update.run(value, key); - return Promise.resolve(true); + __transactions.set({ [key]: value }); + return true; }, - remove: (keys) => { + remove: async (keys) => { + await __db; keys = Array.isArray(keys) ? keys : [keys]; keys = keys.map(namespaceify); - removeMany(keys); - return Promise.resolve(true); + __transactions.remove(keys); + return true; }, - export: () => { - const entries = dump + export: async () => { + await __db; + const entries = __statements.dump .all() .filter(({ key }) => key.startsWith(namespace)) .map(({ key, value }) => [key.slice(namespace.length), value]); - return Promise.resolve(Object.fromEntries(entries)); + return Object.fromEntries(entries); }, - import: (obj) => { + import: async (obj) => { + await __db; const entries = Object.entries(obj) // .map(([key, value]) => [key.slice(namespace.length), value]); - populate(Object.fromEntries(entries)); - return Promise.resolve(true); + __transactions.set(Object.fromEntries(entries)); + return true; }, }; }; diff --git a/src/worker.js b/src/worker.js index 296f2a5..db2dde8 100644 --- a/src/worker.js +++ b/src/worker.js @@ -21,13 +21,18 @@ if (isElectron()) { app.exit(); }; - ipcMain.on("notion-enhancer", (event, message) => { + ipcMain.on("notion-enhancer", (_event, message) => { if (message === "open-menu") { // } else if (message === "reload-app") { reloadApp(); } }); + ipcMain.handle("notion-enhancer", (_event, message) => { + if (message === "get-user-data-folder") { + return app.getPath("userData"); + } + }); } else { const notionUrl = "https://www.notion.so/", isNotionTab = (tab) => tab?.url?.startsWith(notionUrl);