mirror of
				https://github.com/notion-enhancer/notion-enhancer.git
				synced 2025-11-05 00:28:07 +11:00 
			
		
		
		
	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
This commit is contained in:
		
							parent
							
								
									f61ac3d8d9
								
							
						
					
					
						commit
						f999969c13
					
				
							
								
								
									
										28
									
								
								bin.mjs
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								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,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user