mirror of
				https://github.com/notion-enhancer/notion-enhancer.git
				synced 2025-11-04 08:08:08 +11:00 
			
		
		
		
	wip: migrate db ops to use ipc (nodeintegration is disabled in latest app)
This commit is contained in:
		
							parent
							
								
									8e809d4233
								
							
						
					
					
						commit
						bf07257ae8
					
				
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							@ -1,6 +1,6 @@
 | 
				
			|||||||
MIT License
 | 
					MIT License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Copyright (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
					Copyright (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
of this software and associated documentation files (the "Software"), to deal
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								bin.mjs
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								bin.mjs
									
									
									
									
									
								
							@ -2,7 +2,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * notion-enhancer
 | 
					 * notion-enhancer
 | 
				
			||||||
 * (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
					 * (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
				
			||||||
 * (https://notion-enhancer.github.io/) under the MIT license
 | 
					 * (https://notion-enhancer.github.io/) under the MIT license
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -35,8 +35,8 @@
 | 
				
			|||||||
    "notion-enhancer"
 | 
					    "notion-enhancer"
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@electron/asar": "^3.2.2",
 | 
					    "@electron/asar": "^3.2.4",
 | 
				
			||||||
    "arg": "^5.0.2",
 | 
					    "arg": "^5.0.2",
 | 
				
			||||||
    "chalk-template": "^0.4.0"
 | 
					    "chalk-template": "^1.0.0"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * notion-enhancer
 | 
					 * notion-enhancer
 | 
				
			||||||
 * (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
					 * (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
				
			||||||
 * (https://notion-enhancer.github.io/) under the MIT license
 | 
					 * (https://notion-enhancer.github.io/) under the MIT license
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * notion-enhancer
 | 
					 * notion-enhancer
 | 
				
			||||||
 * (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
					 * (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
				
			||||||
 * (https://notion-enhancer.github.io/) under the MIT license
 | 
					 * (https://notion-enhancer.github.io/) under the MIT license
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -40,7 +40,7 @@ const patches = {
 | 
				
			|||||||
                schemePrefix.length,
 | 
					                schemePrefix.length,
 | 
				
			||||||
                -(search.length + hash.length) || undefined
 | 
					                -(search.length + hash.length) || undefined
 | 
				
			||||||
            )}\`;
 | 
					            )}\`;
 | 
				
			||||||
          callback({
 | 
					          return callback({
 | 
				
			||||||
            data: require("fs").createReadStream(require("path").resolve(\`\${__dirname}/\${filePath}\`)),
 | 
					            data: require("fs").createReadStream(require("path").resolve(\`\${__dirname}/\${filePath}\`)),
 | 
				
			||||||
            headers: { "content-type": require("notion-enhancer/vendor/content-types.min.js").get(fileExt) },
 | 
					            headers: { "content-type": require("notion-enhancer/vendor/content-types.min.js").get(fileExt) },
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
@ -52,8 +52,8 @@ const patches = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  "main/systemMenu": async (scriptContent) => {
 | 
					  "main/systemMenu": async (scriptContent) => {
 | 
				
			||||||
    // exposes template for modification
 | 
					    // exposes template for modification
 | 
				
			||||||
    const searchValue = "electron_1.Menu.setApplicationMenu(menu);",
 | 
					    const searchValue = "}\nexports.setupSystemMenu = setupSystemMenu;",
 | 
				
			||||||
      replaceValue = `${searchValue} return template;`;
 | 
					      replaceValue = `    return template;\n${searchValue}`;
 | 
				
			||||||
    if (scriptContent.includes(replaceValue)) return scriptContent;
 | 
					    if (scriptContent.includes(replaceValue)) return scriptContent;
 | 
				
			||||||
    return scriptContent.replace(searchValue, replaceValue);
 | 
					    return scriptContent.replace(searchValue, replaceValue);
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * notion-enhancer
 | 
					 * notion-enhancer
 | 
				
			||||||
 * (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
					 * (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
				
			||||||
 * (https://notion-enhancer.github.io/) under the MIT license
 | 
					 * (https://notion-enhancer.github.io/) under the MIT license
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,88 +0,0 @@
 | 
				
			|||||||
/**
 | 
					 | 
				
			||||||
 * notion-enhancer
 | 
					 | 
				
			||||||
 * (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
					 | 
				
			||||||
 * (https://notion-enhancer.github.io/) under the MIT license
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"use strict";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const platform = navigator.userAgent.includes("Firefox")
 | 
					 | 
				
			||||||
    ? "firefox"
 | 
					 | 
				
			||||||
    : "chromium",
 | 
					 | 
				
			||||||
  version = chrome.runtime.getManifest().version,
 | 
					 | 
				
			||||||
  enhancerUrl = (target) => chrome.runtime.getURL(target);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const readFile = async (file) => {
 | 
					 | 
				
			||||||
    file = file.startsWith("http") ? file : enhancerUrl(file);
 | 
					 | 
				
			||||||
    const res = await fetch(file);
 | 
					 | 
				
			||||||
    return await res.text();
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  readJson = async (file) => {
 | 
					 | 
				
			||||||
    file = file.startsWith("http") ? file : enhancerUrl(file);
 | 
					 | 
				
			||||||
    const res = await fetch(file);
 | 
					 | 
				
			||||||
    return await res.json();
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  reloadApp = () => {
 | 
					 | 
				
			||||||
    chrome.runtime.sendMessage({
 | 
					 | 
				
			||||||
      channel: "notion-enhancer",
 | 
					 | 
				
			||||||
      message: "reload-app",
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const sendMessage = (channel, message) => {
 | 
					 | 
				
			||||||
    chrome.runtime.sendMessage({ channel, message });
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  onMessage = (channel, listener) => {
 | 
					 | 
				
			||||||
    chrome.runtime.onMessage.addListener((msg) => {
 | 
					 | 
				
			||||||
      if (msg?.channel === channel) listener(msg.message);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const initDatabase = (namespace, fallbacks = {}) => {
 | 
					 | 
				
			||||||
  if (Array.isArray(namespace)) namespace = namespace.join("__");
 | 
					 | 
				
			||||||
  namespace = namespace ? namespace + "__" : "";
 | 
					 | 
				
			||||||
  const namespaceify = (key) =>
 | 
					 | 
				
			||||||
    key.startsWith(namespace) ? key : namespace + key;
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    get: async (key) => {
 | 
					 | 
				
			||||||
      const fallback = fallbacks[key];
 | 
					 | 
				
			||||||
      key = namespaceify(key);
 | 
					 | 
				
			||||||
      return (await chrome.storage.local.get([key]))[key] ?? fallback;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    set: (key, value) => {
 | 
					 | 
				
			||||||
      key = namespaceify(key);
 | 
					 | 
				
			||||||
      return chrome.storage.local.set({ [key]: value });
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    remove: (keys) => {
 | 
					 | 
				
			||||||
      keys = Array.isArray(keys) ? keys : [keys];
 | 
					 | 
				
			||||||
      keys = keys.map(namespaceify);
 | 
					 | 
				
			||||||
      return chrome.storage.local.remove(keys);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    export: async () => {
 | 
					 | 
				
			||||||
      const obj = await chrome.storage.local.get();
 | 
					 | 
				
			||||||
      if (!namespace) return obj;
 | 
					 | 
				
			||||||
      const entries = Object.entries(obj)
 | 
					 | 
				
			||||||
        .filter(([key]) => key.startsWith(namespace))
 | 
					 | 
				
			||||||
        .map(([key, value]) => [key.slice(namespace.length), value]);
 | 
					 | 
				
			||||||
      return Object.fromEntries(entries);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    import: (obj) => {
 | 
					 | 
				
			||||||
      const entries = Object.entries(obj) //
 | 
					 | 
				
			||||||
        .map(([key, value]) => [namespace + key, value]);
 | 
					 | 
				
			||||||
      return chrome.storage.local.set(Object.fromEntries(entries));
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
globalThis.__enhancerApi ??= {};
 | 
					 | 
				
			||||||
Object.assign(globalThis.__enhancerApi, {
 | 
					 | 
				
			||||||
  platform,
 | 
					 | 
				
			||||||
  version,
 | 
					 | 
				
			||||||
  enhancerUrl,
 | 
					 | 
				
			||||||
  readFile,
 | 
					 | 
				
			||||||
  readJson,
 | 
					 | 
				
			||||||
  reloadApp,
 | 
					 | 
				
			||||||
  sendMessage,
 | 
					 | 
				
			||||||
  onMessage,
 | 
					 | 
				
			||||||
  initDatabase,
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@ -1,160 +0,0 @@
 | 
				
			|||||||
/**
 | 
					 | 
				
			||||||
 * notion-enhancer
 | 
					 | 
				
			||||||
 * (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
					 | 
				
			||||||
 * (https://notion-enhancer.github.io/) under the MIT license
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"use strict";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const fs = require("fs"),
 | 
					 | 
				
			||||||
  path = require("path"),
 | 
					 | 
				
			||||||
  notionRequire = (target) => require(`../../../${target}`);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const platform = process.platform,
 | 
					 | 
				
			||||||
  version = require("notion-enhancer/package.json").version,
 | 
					 | 
				
			||||||
  enhancerUrl = (target) =>
 | 
					 | 
				
			||||||
    `notion://www.notion.so/__notion-enhancer/${target.replace(/^\//, "")}`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const readFile = (file) => {
 | 
					 | 
				
			||||||
    // prettier-ignore
 | 
					 | 
				
			||||||
    file = file.replace(/^https:\/\/www\.notion\.so\//, "notion://www.notion.so/");
 | 
					 | 
				
			||||||
    const useFetch = file.startsWith("http") || file.startsWith("notion://");
 | 
					 | 
				
			||||||
    if (useFetch) return fetch(file).then((res) => res.text());
 | 
					 | 
				
			||||||
    return fs.readFileSync(path.resolve(`${__dirname}/../${file}`), "utf-8");
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  readJson = (file) => {
 | 
					 | 
				
			||||||
    // prettier-ignore
 | 
					 | 
				
			||||||
    file = file.replace(/^https:\/\/www\.notion\.so\//, "notion://www.notion.so/");
 | 
					 | 
				
			||||||
    const useFetch = file.startsWith("http") || file.startsWith("notion://");
 | 
					 | 
				
			||||||
    if (useFetch) return fetch(file).then((res) => res.json());
 | 
					 | 
				
			||||||
    return require(path.resolve(`${__dirname}/../${file}`));
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  reloadApp = () => {
 | 
					 | 
				
			||||||
    const { app, ipcRenderer } = require("electron");
 | 
					 | 
				
			||||||
    if (app) {
 | 
					 | 
				
			||||||
      const args = process.argv.slice(1).filter((arg) => arg !== "--startup");
 | 
					 | 
				
			||||||
      app.relaunch({ args });
 | 
					 | 
				
			||||||
      app.exit();
 | 
					 | 
				
			||||||
    } else ipcRenderer.send("notion-enhancer", "reload-app");
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const sendMessage = (channel, message) => {
 | 
					 | 
				
			||||||
    const { ipcRenderer } = require("electron");
 | 
					 | 
				
			||||||
    ipcRenderer.send(channel, message);
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  onMessage = (channel, listener) => {
 | 
					 | 
				
			||||||
    const { ipcRenderer } = require("electron");
 | 
					 | 
				
			||||||
    ipcRenderer.on(channel, listener);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  __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 = sqlite(path.resolve(`${userData}/notion-enhancer.db`)),
 | 
					 | 
				
			||||||
      init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} (
 | 
					 | 
				
			||||||
          key     TEXT PRIMARY KEY,
 | 
					 | 
				
			||||||
          value   TEXT
 | 
					 | 
				
			||||||
        )`);
 | 
					 | 
				
			||||||
    init.run();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // schema:
 | 
					 | 
				
			||||||
    // - ("agreedToTerms") -> string: semver
 | 
					 | 
				
			||||||
    // - ("lastTelemetryPing") -> string: iso
 | 
					 | 
				
			||||||
    // - ("telemetryEnabled") -> boolean
 | 
					 | 
				
			||||||
    // - ("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 {
 | 
					 | 
				
			||||||
    get: async (key) => {
 | 
					 | 
				
			||||||
      await __db;
 | 
					 | 
				
			||||||
      const fallback = fallbacks[key];
 | 
					 | 
				
			||||||
      key = namespaceify(key);
 | 
					 | 
				
			||||||
      try {
 | 
					 | 
				
			||||||
        const value = JSON.parse(__statements.select.get(key)?.value);
 | 
					 | 
				
			||||||
        return value ?? fallback;
 | 
					 | 
				
			||||||
      } catch {}
 | 
					 | 
				
			||||||
      return fallback;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    set: async (key, value) => {
 | 
					 | 
				
			||||||
      await __db;
 | 
					 | 
				
			||||||
      key = namespaceify(key);
 | 
					 | 
				
			||||||
      value = JSON.stringify(value);
 | 
					 | 
				
			||||||
      __transactions.set({ [key]: value });
 | 
					 | 
				
			||||||
      return true;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    remove: async (keys) => {
 | 
					 | 
				
			||||||
      await __db;
 | 
					 | 
				
			||||||
      keys = Array.isArray(keys) ? keys : [keys];
 | 
					 | 
				
			||||||
      keys = keys.map(namespaceify);
 | 
					 | 
				
			||||||
      __transactions.remove(keys);
 | 
					 | 
				
			||||||
      return true;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    export: async () => {
 | 
					 | 
				
			||||||
      await __db;
 | 
					 | 
				
			||||||
      const entries = __statements.dump
 | 
					 | 
				
			||||||
        .all()
 | 
					 | 
				
			||||||
        .filter(({ key }) => key.startsWith(namespace))
 | 
					 | 
				
			||||||
        .map(({ key, value }) => [key.slice(namespace.length), value]);
 | 
					 | 
				
			||||||
      return Object.fromEntries(entries);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    import: async (obj) => {
 | 
					 | 
				
			||||||
      await __db;
 | 
					 | 
				
			||||||
      const entries = Object.entries(obj) //
 | 
					 | 
				
			||||||
        .map(([key, value]) => [key.slice(namespace.length), value]);
 | 
					 | 
				
			||||||
      __transactions.set(Object.fromEntries(entries));
 | 
					 | 
				
			||||||
      return true;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
globalThis.__enhancerApi ??= {};
 | 
					 | 
				
			||||||
Object.assign(globalThis.__enhancerApi, {
 | 
					 | 
				
			||||||
  notionRequire,
 | 
					 | 
				
			||||||
  platform,
 | 
					 | 
				
			||||||
  version,
 | 
					 | 
				
			||||||
  enhancerUrl,
 | 
					 | 
				
			||||||
  readFile,
 | 
					 | 
				
			||||||
  readJson,
 | 
					 | 
				
			||||||
  reloadApp,
 | 
					 | 
				
			||||||
  sendMessage,
 | 
					 | 
				
			||||||
  onMessage,
 | 
					 | 
				
			||||||
  initDatabase,
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@ -49,7 +49,7 @@ attachObserver();
 | 
				
			|||||||
let keyListeners = [];
 | 
					let keyListeners = [];
 | 
				
			||||||
// accelerators approximately match electron accelerators.
 | 
					// accelerators approximately match electron accelerators.
 | 
				
			||||||
// logic used when recording hotkeys in menu matches logic used
 | 
					// logic used when recording hotkeys in menu matches logic used
 | 
				
			||||||
// when triggering hotkeys ∴ detection should be reliable.
 | 
					// when triggering hotkeys => detection should be reliable.
 | 
				
			||||||
// default hotkeys using "alt" may trigger an altcode or
 | 
					// default hotkeys using "alt" may trigger an altcode or
 | 
				
			||||||
// accented character on some keyboard layouts (not recommended).
 | 
					// accented character on some keyboard layouts (not recommended).
 | 
				
			||||||
const modifierAliases = [
 | 
					const modifierAliases = [
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * notion-enhancer
 | 
					 * notion-enhancer
 | 
				
			||||||
 * (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
					 * (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
				
			||||||
 * (https://notion-enhancer.github.io/) under the MIT license
 | 
					 * (https://notion-enhancer.github.io/) under the MIT license
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										150
									
								
								src/api/system.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/api/system.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,150 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * notion-enhancer
 | 
				
			||||||
 | 
					 * (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
				
			||||||
 | 
					 * (https://notion-enhancer.github.io/) under the MIT license
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"use strict";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const IS_ELECTRON = typeof module !== "undefined";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// expected values: 'linux', 'win32', 'darwin' (== macos), 'firefox'
 | 
				
			||||||
 | 
					// and 'chromium' (inc. chromium-based browsers like edge and brave)
 | 
				
			||||||
 | 
					// other possible values: 'aix', 'freebsd', 'openbsd', 'sunos'
 | 
				
			||||||
 | 
					const platform = IS_ELECTRON
 | 
				
			||||||
 | 
					    ? process.platform
 | 
				
			||||||
 | 
					    : navigator.userAgent.includes("Firefox")
 | 
				
			||||||
 | 
					    ? "firefox"
 | 
				
			||||||
 | 
					    : "chromium",
 | 
				
			||||||
 | 
					  // currently installed version of the notion-enhancer
 | 
				
			||||||
 | 
					  version = IS_ELECTRON
 | 
				
			||||||
 | 
					    ? require("notion-enhancer/package.json").version
 | 
				
			||||||
 | 
					    : chrome.runtime.getManifest().version,
 | 
				
			||||||
 | 
					  // forms a url to a notion-enhancer asset or source file
 | 
				
			||||||
 | 
					  // that can be accessed reliably over http
 | 
				
			||||||
 | 
					  enhancerUrl = (target) =>
 | 
				
			||||||
 | 
					    IS_ELECTRON
 | 
				
			||||||
 | 
					      ? `notion://www.notion.so/__notion-enhancer/${target.replace(/^\//, "")}`
 | 
				
			||||||
 | 
					      : chrome.runtime.getURL(target),
 | 
				
			||||||
 | 
					  // should only be used from an electron main process, does nothing elsewhere
 | 
				
			||||||
 | 
					  notionRequire = (target) => IS_ELECTRON && require(`../../../${target}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let __port;
 | 
				
			||||||
 | 
					const onMessage = (channel, listener) => {
 | 
				
			||||||
 | 
					    // from worker to client
 | 
				
			||||||
 | 
					    if (IS_ELECTRON) {
 | 
				
			||||||
 | 
					      const { ipcRenderer } = require("electron");
 | 
				
			||||||
 | 
					      ipcRenderer.on(channel, listener);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      __port ??= chrome.runtime.connect();
 | 
				
			||||||
 | 
					      __port.onMessage.addListener((msg) => {
 | 
				
			||||||
 | 
					        if (msg?.channel !== channel || msg?.invocation) return;
 | 
				
			||||||
 | 
					        listener(msg.message);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  sendMessage = (channel, message) => {
 | 
				
			||||||
 | 
					    // to worker from client
 | 
				
			||||||
 | 
					    if (IS_ELECTRON) {
 | 
				
			||||||
 | 
					      const { ipcRenderer } = require("electron");
 | 
				
			||||||
 | 
					      ipcRenderer.send(channel, message);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      __port ??= chrome.runtime.connect();
 | 
				
			||||||
 | 
					      __port.postMessage({ channel, message });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  invokeInWorker = (channel, message) => {
 | 
				
			||||||
 | 
					    if (IS_ELECTRON) {
 | 
				
			||||||
 | 
					      const { ipcRenderer } = require("electron");
 | 
				
			||||||
 | 
					      return ipcRenderer.invoke(channel, message);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // polyfills the electron.ipcRenderer.invoke method in
 | 
				
			||||||
 | 
					      // the browser: uses a long-lived ipc connection to
 | 
				
			||||||
 | 
					      // pass messages and handle responses asynchronously
 | 
				
			||||||
 | 
					      let fulfilled;
 | 
				
			||||||
 | 
					      __port ??= chrome.runtime.connect();
 | 
				
			||||||
 | 
					      const id = crypto.randomUUID();
 | 
				
			||||||
 | 
					      return new Promise((res, rej) => {
 | 
				
			||||||
 | 
					        __port.onMessage.addListener((msg) => {
 | 
				
			||||||
 | 
					          if (msg?.invocation !== id || fulfilled) return;
 | 
				
			||||||
 | 
					          fulfilled = true;
 | 
				
			||||||
 | 
					          res(msg.message);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        __port.postMessage({ channel, message, invocation: id });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const readFile = (file) => {
 | 
				
			||||||
 | 
					    if (IS_ELECTRON) {
 | 
				
			||||||
 | 
					      // read directly from filesys if possible,
 | 
				
			||||||
 | 
					      // treating notion-enhancer/src as fs root
 | 
				
			||||||
 | 
					      if (!file.startsWith("http")) {
 | 
				
			||||||
 | 
					        const fsp = require("fs/promises"),
 | 
				
			||||||
 | 
					          { resolve } = require("path");
 | 
				
			||||||
 | 
					        return fsp.readFile(resolve(`${__dirname}/../${file}`), "utf-8");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // prefer using versions of files cached by the app
 | 
				
			||||||
 | 
					      // or routed through the notion-enhancer's url interception
 | 
				
			||||||
 | 
					      const notionProtocol = "notion://www.notion.so/";
 | 
				
			||||||
 | 
					      file = file.replace(/^https:\/\/www\.notion\.so\//, notionProtocol);
 | 
				
			||||||
 | 
					    } else file = file.startsWith("http") ? file : enhancerUrl(file);
 | 
				
			||||||
 | 
					    return fetch(file).then((res) => res.text());
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  readJson = (file) => {
 | 
				
			||||||
 | 
					    // as above, uses require instead of readFile
 | 
				
			||||||
 | 
					    // and res.json() instead of res.text() to return
 | 
				
			||||||
 | 
					    // json content of file in object form
 | 
				
			||||||
 | 
					    if (IS_ELECTRON) {
 | 
				
			||||||
 | 
					      if (!file.startsWith("http")) {
 | 
				
			||||||
 | 
					        const { resolve } = require("path");
 | 
				
			||||||
 | 
					        return require(resolve(`${__dirname}/../${file}`), "utf-8");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const notionProtocol = "notion://www.notion.so/";
 | 
				
			||||||
 | 
					      file = file.replace(/^https:\/\/www\.notion\.so\//, notionProtocol);
 | 
				
			||||||
 | 
					    } else file = file.startsWith("http") ? file : enhancerUrl(file);
 | 
				
			||||||
 | 
					    return fetch(file).then((res) => res.json());
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  reloadApp = () => {
 | 
				
			||||||
 | 
					    if (IS_ELECTRON && require("electron").app) {
 | 
				
			||||||
 | 
					      const { app } = require("electron"),
 | 
				
			||||||
 | 
					        args = process.argv.slice(1).filter((arg) => arg !== "--startup");
 | 
				
			||||||
 | 
					      app.relaunch({ args });
 | 
				
			||||||
 | 
					      app.exit();
 | 
				
			||||||
 | 
					    } else sendMessage("notion-enhancer", "reload-app");
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const initDatabase = (namespace, fallbacks = {}) => {
 | 
				
			||||||
 | 
					  // all db operations are performed via ipc:
 | 
				
			||||||
 | 
					  // with nodeintegration disabled, sqlite cannot
 | 
				
			||||||
 | 
					  // be require()-d from the renderer process
 | 
				
			||||||
 | 
					  const operation = (type, args = {}) =>
 | 
				
			||||||
 | 
					    invokeInWorker("notion-enhancer:db", {
 | 
				
			||||||
 | 
					      namespace,
 | 
				
			||||||
 | 
					      fallbacks,
 | 
				
			||||||
 | 
					      operation: type,
 | 
				
			||||||
 | 
					      ...args,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    get: (key) => operation("get", { key }),
 | 
				
			||||||
 | 
					    set: (key, value) => operation("set", { key, value }),
 | 
				
			||||||
 | 
					    remove: (keys) => operation("remove", { keys }),
 | 
				
			||||||
 | 
					    export: () => operation("export"),
 | 
				
			||||||
 | 
					    import: (obj) => operation("import", { obj }),
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					globalThis.__enhancerApi ??= {};
 | 
				
			||||||
 | 
					Object.assign(globalThis.__enhancerApi, {
 | 
				
			||||||
 | 
					  platform,
 | 
				
			||||||
 | 
					  version,
 | 
				
			||||||
 | 
					  enhancerUrl,
 | 
				
			||||||
 | 
					  notionRequire,
 | 
				
			||||||
 | 
					  onMessage,
 | 
				
			||||||
 | 
					  sendMessage,
 | 
				
			||||||
 | 
					  invokeInWorker,
 | 
				
			||||||
 | 
					  readFile,
 | 
				
			||||||
 | 
					  readJson,
 | 
				
			||||||
 | 
					  reloadApp,
 | 
				
			||||||
 | 
					  initDatabase,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -43,9 +43,9 @@ function List({ id, mods, description }) {
 | 
				
			|||||||
      const _get = () => isEnabled(mod.id),
 | 
					      const _get = () => isEnabled(mod.id),
 | 
				
			||||||
        _set = async (enabled) => {
 | 
					        _set = async (enabled) => {
 | 
				
			||||||
          await setEnabled(mod.id, enabled);
 | 
					          await setEnabled(mod.id, enabled);
 | 
				
			||||||
          // only one theme of each mode may be
 | 
					          // only one theme may be enabled per
 | 
				
			||||||
          // enabled at a time ∴ disable others
 | 
					          // mode at a time => auto-disable other
 | 
				
			||||||
          // on theme of same mode enabled
 | 
					          // enabled themes of matching mode
 | 
				
			||||||
          if (enabled && id === "themes") {
 | 
					          if (enabled && id === "themes") {
 | 
				
			||||||
            const isDark = mod.tags.includes("dark"),
 | 
					            const isDark = mod.tags.includes("dark"),
 | 
				
			||||||
              isLight = mod.tags.includes("light");
 | 
					              isLight = mod.tags.includes("light");
 | 
				
			||||||
 | 
				
			|||||||
@ -197,9 +197,9 @@ useState(["rerender"], async () => {
 | 
				
			|||||||
  if (!theme || !icon) return;
 | 
					  if (!theme || !icon) return;
 | 
				
			||||||
  // chrome extensions run in an isolated execution context
 | 
					  // chrome extensions run in an isolated execution context
 | 
				
			||||||
  // but extension:// pages can access chrome apis
 | 
					  // but extension:// pages can access chrome apis
 | 
				
			||||||
  // ∴ notion-enhancer api is imported directly
 | 
					  // => notion-enhancer api is imported directly
 | 
				
			||||||
  if (typeof globalThis.__enhancerApi === "undefined") {
 | 
					  if (typeof globalThis.__enhancerApi === "undefined") {
 | 
				
			||||||
    await import("../../api/browser.js");
 | 
					    await import("../../api/system.js");
 | 
				
			||||||
    // in electron this isn't necessary, as a) scripts are
 | 
					    // in electron this isn't necessary, as a) scripts are
 | 
				
			||||||
    // not running in an isolated execution context and b)
 | 
					    // not running in an isolated execution context and b)
 | 
				
			||||||
    // the notion:// protocol csp bypass allows scripts to
 | 
					    // the notion:// protocol csp bypass allows scripts to
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ const isElectron = () => {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (isElectron()) {
 | 
					if (isElectron()) {
 | 
				
			||||||
  require("./api/electron.cjs");
 | 
					  require("./api/system.js");
 | 
				
			||||||
  require("./api/mods.js");
 | 
					  require("./api/mods.js");
 | 
				
			||||||
  const { enhancerUrl } = globalThis.__enhancerApi,
 | 
					  const { enhancerUrl } = globalThis.__enhancerApi,
 | 
				
			||||||
    { getMods, isEnabled, modDatabase } = globalThis.__enhancerApi;
 | 
					    { getMods, isEnabled, modDatabase } = globalThis.__enhancerApi;
 | 
				
			||||||
@ -48,7 +48,7 @@ if (isElectron()) {
 | 
				
			|||||||
} else {
 | 
					} else {
 | 
				
			||||||
  // clientStyles
 | 
					  // clientStyles
 | 
				
			||||||
  // clientScripts
 | 
					  // clientScripts
 | 
				
			||||||
  import(chrome.runtime.getURL("/api/browser.js")).then(() => {
 | 
					  import(chrome.runtime.getURL("/api/system.js")).then(() => {
 | 
				
			||||||
    import(chrome.runtime.getURL("/load.mjs"));
 | 
					    import(chrome.runtime.getURL("/load.mjs"));
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										122
									
								
								src/worker.js
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								src/worker.js
									
									
									
									
									
								
							@ -1,19 +1,14 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * notion-enhancer
 | 
					 * notion-enhancer
 | 
				
			||||||
 * (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
					 * (c) 2023 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 | 
				
			||||||
 * (https://notion-enhancer.github.io/) under the MIT license
 | 
					 * (https://notion-enhancer.github.io/) under the MIT license
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"use strict";
 | 
					"use strict";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const isElectron = () => {
 | 
					const IS_ELECTRON = typeof module !== "undefined";
 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    return typeof module !== "undefined";
 | 
					 | 
				
			||||||
  } catch {}
 | 
					 | 
				
			||||||
  return false;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (isElectron()) {
 | 
					if (IS_ELECTRON) {
 | 
				
			||||||
  const { app, ipcMain } = require("electron"),
 | 
					  const { app, ipcMain } = require("electron"),
 | 
				
			||||||
    reloadApp = () => {
 | 
					    reloadApp = () => {
 | 
				
			||||||
      const args = process.argv.slice(1).filter((arg) => arg !== "--startup");
 | 
					      const args = process.argv.slice(1).filter((arg) => arg !== "--startup");
 | 
				
			||||||
@ -23,7 +18,7 @@ if (isElectron()) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  ipcMain.on("notion-enhancer", (_event, message) => {
 | 
					  ipcMain.on("notion-enhancer", (_event, message) => {
 | 
				
			||||||
    if (message === "open-menu") {
 | 
					    if (message === "open-menu") {
 | 
				
			||||||
      //
 | 
					      // todo
 | 
				
			||||||
    } else if (message === "reload-app") {
 | 
					    } else if (message === "reload-app") {
 | 
				
			||||||
      reloadApp();
 | 
					      reloadApp();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -62,6 +57,8 @@ if (isElectron()) {
 | 
				
			|||||||
      notionTabs.forEach((tab) => chrome.tabs.reload(tab.id));
 | 
					      notionTabs.forEach((tab) => chrome.tabs.reload(tab.id));
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // listen for invoke: https://developer.chrome.com/docs/extensions/mv3/messaging/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  chrome.action.onClicked.addListener(openEnhancerMenu);
 | 
					  chrome.action.onClicked.addListener(openEnhancerMenu);
 | 
				
			||||||
  chrome.runtime.onMessage.addListener((msg, sender) => {
 | 
					  chrome.runtime.onMessage.addListener((msg, sender) => {
 | 
				
			||||||
    if (msg?.channel !== "notion-enhancer") return;
 | 
					    if (msg?.channel !== "notion-enhancer") return;
 | 
				
			||||||
@ -78,3 +75,110 @@ if (isElectron()) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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:
 | 
				
			||||||
 | 
					  // - ("agreedToTerms") -> string: semver
 | 
				
			||||||
 | 
					  // - ("lastTelemetryPing") -> string: iso
 | 
				
			||||||
 | 
					  // - ("telemetryEnabled") -> boolean
 | 
				
			||||||
 | 
					  // - ("profileIds") -> $profileId[]
 | 
				
			||||||
 | 
					  // - ("activeProfile") -> $profileId
 | 
				
			||||||
 | 
					  // - $profileId: ("profileName") -> string
 | 
				
			||||||
 | 
					  // - $profileId__enabledMods: ($modId) -> boolean
 | 
				
			||||||
 | 
					  // - $profileId__$modId: ($optionKey) -> value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  __db ??= (async () => {
 | 
				
			||||||
 | 
					    if (!IS_ELECTRON) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const table = "kvstore",
 | 
				
			||||||
 | 
					      { app } = require("electron"),
 | 
				
			||||||
 | 
					      { resolve } = require("path"),
 | 
				
			||||||
 | 
					      sqlite = require("better-sqlite3"),
 | 
				
			||||||
 | 
					      db = sqlite(resolve(`${app.getPath("userData")}/notion-enhancer.db`)),
 | 
				
			||||||
 | 
					      init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} (
 | 
				
			||||||
 | 
					        key     TEXT PRIMARY KEY,
 | 
				
			||||||
 | 
					        value   TEXT
 | 
				
			||||||
 | 
					      )`);
 | 
				
			||||||
 | 
					    init.run();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    __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 {
 | 
				
			||||||
 | 
					    async get(key) {
 | 
				
			||||||
 | 
					      await __db;
 | 
				
			||||||
 | 
					      let value;
 | 
				
			||||||
 | 
					      const fallback = fallbacks[key];
 | 
				
			||||||
 | 
					      key = namespaceify(key);
 | 
				
			||||||
 | 
					      if (IS_ELECTRON) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					          value = JSON.parse(__statements.select.get(key)?.value);
 | 
				
			||||||
 | 
					        } catch {}
 | 
				
			||||||
 | 
					      } else value = (await chrome.storage.local.get([key]))[key];
 | 
				
			||||||
 | 
					      return value ?? fallback;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    async set(key, value) {
 | 
				
			||||||
 | 
					      await __db;
 | 
				
			||||||
 | 
					      key = namespaceify(key);
 | 
				
			||||||
 | 
					      return IS_ELECTRON
 | 
				
			||||||
 | 
					        ? // returns true instead of transaction completion data type
 | 
				
			||||||
 | 
					          (__transactions.set({ [key]: JSON.stringify(value) }), true)
 | 
				
			||||||
 | 
					        : chrome.storage.local.set({ [key]: value });
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    async remove(keys) {
 | 
				
			||||||
 | 
					      await __db;
 | 
				
			||||||
 | 
					      keys = Array.isArray(keys) ? keys : [keys];
 | 
				
			||||||
 | 
					      keys = keys.map(namespaceify);
 | 
				
			||||||
 | 
					      return IS_ELECTRON
 | 
				
			||||||
 | 
					        ? (__transactions.remove(keys), true)
 | 
				
			||||||
 | 
					        : chrome.storage.local.remove(keys);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    async export() {
 | 
				
			||||||
 | 
					      await __db;
 | 
				
			||||||
 | 
					      // returns key/value pairs within scope w/out namespace
 | 
				
			||||||
 | 
					      // prefix e.g. to streamline importing from one profile and
 | 
				
			||||||
 | 
					      // then into another (where a diff. namespace is used)
 | 
				
			||||||
 | 
					      let entries = IS_ELECTRON
 | 
				
			||||||
 | 
					        ? __statements.dump.all().map(({ key, value }) => [key, value])
 | 
				
			||||||
 | 
					        : Object.entries(await chrome.storage.local.get());
 | 
				
			||||||
 | 
					      entries = entries
 | 
				
			||||||
 | 
					        .filter(([key]) => key.startsWith(namespace))
 | 
				
			||||||
 | 
					        .map(([key, value]) => [key.slice(namespace.length), value]);
 | 
				
			||||||
 | 
					      return Object.fromEntries(entries);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    async import(obj) {
 | 
				
			||||||
 | 
					      await __db;
 | 
				
			||||||
 | 
					      let entries = Object.entries(obj);
 | 
				
			||||||
 | 
					      entries = entries.map(([key, value]) => [namespace + key, value]);
 | 
				
			||||||
 | 
					      entries = Object.fromEntries(entries);
 | 
				
			||||||
 | 
					      return IS_ELECTRON
 | 
				
			||||||
 | 
					        ? (__transactions.set(entries), true)
 | 
				
			||||||
 | 
					        : chrome.storage.local.set(entries);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										102
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										102
									
								
								yarn.lock
									
									
									
									
									
								
							@ -5,54 +5,17 @@ __metadata:
 | 
				
			|||||||
  version: 6
 | 
					  version: 6
 | 
				
			||||||
  cacheKey: 8
 | 
					  cacheKey: 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@electron/asar@npm:^3.2.2":
 | 
					"@electron/asar@npm:^3.2.4":
 | 
				
			||||||
  version: 3.2.2
 | 
					  version: 3.2.4
 | 
				
			||||||
  resolution: "@electron/asar@npm:3.2.2"
 | 
					  resolution: "@electron/asar@npm:3.2.4"
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@types/glob": ^7.1.1
 | 
					 | 
				
			||||||
    chromium-pickle-js: ^0.2.0
 | 
					    chromium-pickle-js: ^0.2.0
 | 
				
			||||||
    commander: ^5.0.0
 | 
					    commander: ^5.0.0
 | 
				
			||||||
    glob: ^7.1.6
 | 
					    glob: ^7.1.6
 | 
				
			||||||
    minimatch: ^3.0.4
 | 
					    minimatch: ^3.0.4
 | 
				
			||||||
  dependenciesMeta:
 | 
					 | 
				
			||||||
    "@types/glob":
 | 
					 | 
				
			||||||
      optional: true
 | 
					 | 
				
			||||||
  bin:
 | 
					  bin:
 | 
				
			||||||
    asar: bin/asar.js
 | 
					    asar: bin/asar.js
 | 
				
			||||||
  checksum: 38a3b4a47180f2033a599421175f03706941ba05a32591a639127f6374e0007c6a7c8bde550129de394f4072a0bf39c24aea202540fe1faba6d74b4181c007a8
 | 
					  checksum: 06e3e8fe7c894f7e7727410af5a9957ec77088f775b22441acf4ef718a9e6642a4dc1672f77ee1ce325fc367c8d59ac1e02f7db07869c8ced8a00132a3b54643
 | 
				
			||||||
  languageName: node
 | 
					 | 
				
			||||||
  linkType: hard
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"@types/glob@npm:^7.1.1":
 | 
					 | 
				
			||||||
  version: 7.2.0
 | 
					 | 
				
			||||||
  resolution: "@types/glob@npm:7.2.0"
 | 
					 | 
				
			||||||
  dependencies:
 | 
					 | 
				
			||||||
    "@types/minimatch": "*"
 | 
					 | 
				
			||||||
    "@types/node": "*"
 | 
					 | 
				
			||||||
  checksum: 6ae717fedfdfdad25f3d5a568323926c64f52ef35897bcac8aca8e19bc50c0bd84630bbd063e5d52078b2137d8e7d3c26eabebd1a2f03ff350fff8a91e79fc19
 | 
					 | 
				
			||||||
  languageName: node
 | 
					 | 
				
			||||||
  linkType: hard
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"@types/minimatch@npm:*":
 | 
					 | 
				
			||||||
  version: 5.1.2
 | 
					 | 
				
			||||||
  resolution: "@types/minimatch@npm:5.1.2"
 | 
					 | 
				
			||||||
  checksum: 0391a282860c7cb6fe262c12b99564732401bdaa5e395bee9ca323c312c1a0f45efbf34dce974682036e857db59a5c9b1da522f3d6055aeead7097264c8705a8
 | 
					 | 
				
			||||||
  languageName: node
 | 
					 | 
				
			||||||
  linkType: hard
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"@types/node@npm:*":
 | 
					 | 
				
			||||||
  version: 18.11.11
 | 
					 | 
				
			||||||
  resolution: "@types/node@npm:18.11.11"
 | 
					 | 
				
			||||||
  checksum: c4b1176a8f1714a3ee3fc2a5e1d568b0cd50209000282db5c68154b3c975952928dbb834ef3a0ce55bd7b345ae29f2cbf4a34635a070294d135a24254231386a
 | 
					 | 
				
			||||||
  languageName: node
 | 
					 | 
				
			||||||
  linkType: hard
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"ansi-styles@npm:^4.1.0":
 | 
					 | 
				
			||||||
  version: 4.3.0
 | 
					 | 
				
			||||||
  resolution: "ansi-styles@npm:4.3.0"
 | 
					 | 
				
			||||||
  dependencies:
 | 
					 | 
				
			||||||
    color-convert: ^2.0.1
 | 
					 | 
				
			||||||
  checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4
 | 
					 | 
				
			||||||
  languageName: node
 | 
					  languageName: node
 | 
				
			||||||
  linkType: hard
 | 
					  linkType: hard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -80,22 +43,19 @@ __metadata:
 | 
				
			|||||||
  languageName: node
 | 
					  languageName: node
 | 
				
			||||||
  linkType: hard
 | 
					  linkType: hard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"chalk-template@npm:^0.4.0":
 | 
					"chalk-template@npm:^1.0.0":
 | 
				
			||||||
  version: 0.4.0
 | 
					  version: 1.0.0
 | 
				
			||||||
  resolution: "chalk-template@npm:0.4.0"
 | 
					  resolution: "chalk-template@npm:1.0.0"
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    chalk: ^4.1.2
 | 
					    chalk: ^5.2.0
 | 
				
			||||||
  checksum: 6c706802a79a7963cbce18f022b046fe86e438a67843151868852f80ea7346e975a6a9749991601e7e5d3b6a6c4852a04c53dc966a9a3d04031bd0e0ed53c819
 | 
					  checksum: 2cd8ae86d7e2ccc546a8fa93871931f7e5731b812e867be1bb77487f83ad6bd657dd25483a99dd0e4d615163551fde4457e48995597b69d58b8f1f633bc21952
 | 
				
			||||||
  languageName: node
 | 
					  languageName: node
 | 
				
			||||||
  linkType: hard
 | 
					  linkType: hard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"chalk@npm:^4.1.2":
 | 
					"chalk@npm:^5.2.0":
 | 
				
			||||||
  version: 4.1.2
 | 
					  version: 5.2.0
 | 
				
			||||||
  resolution: "chalk@npm:4.1.2"
 | 
					  resolution: "chalk@npm:5.2.0"
 | 
				
			||||||
  dependencies:
 | 
					  checksum: 03d8060277de6cf2fd567dc25fcf770593eb5bb85f460ce443e49255a30ff1242edd0c90a06a03803b0466ff0687a939b41db1757bec987113e83de89a003caa
 | 
				
			||||||
    ansi-styles: ^4.1.0
 | 
					 | 
				
			||||||
    supports-color: ^7.1.0
 | 
					 | 
				
			||||||
  checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc
 | 
					 | 
				
			||||||
  languageName: node
 | 
					  languageName: node
 | 
				
			||||||
  linkType: hard
 | 
					  linkType: hard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -106,22 +66,6 @@ __metadata:
 | 
				
			|||||||
  languageName: node
 | 
					  languageName: node
 | 
				
			||||||
  linkType: hard
 | 
					  linkType: hard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"color-convert@npm:^2.0.1":
 | 
					 | 
				
			||||||
  version: 2.0.1
 | 
					 | 
				
			||||||
  resolution: "color-convert@npm:2.0.1"
 | 
					 | 
				
			||||||
  dependencies:
 | 
					 | 
				
			||||||
    color-name: ~1.1.4
 | 
					 | 
				
			||||||
  checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336
 | 
					 | 
				
			||||||
  languageName: node
 | 
					 | 
				
			||||||
  linkType: hard
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"color-name@npm:~1.1.4":
 | 
					 | 
				
			||||||
  version: 1.1.4
 | 
					 | 
				
			||||||
  resolution: "color-name@npm:1.1.4"
 | 
					 | 
				
			||||||
  checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610
 | 
					 | 
				
			||||||
  languageName: node
 | 
					 | 
				
			||||||
  linkType: hard
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"commander@npm:^5.0.0":
 | 
					"commander@npm:^5.0.0":
 | 
				
			||||||
  version: 5.1.0
 | 
					  version: 5.1.0
 | 
				
			||||||
  resolution: "commander@npm:5.1.0"
 | 
					  resolution: "commander@npm:5.1.0"
 | 
				
			||||||
@ -157,13 +101,6 @@ __metadata:
 | 
				
			|||||||
  languageName: node
 | 
					  languageName: node
 | 
				
			||||||
  linkType: hard
 | 
					  linkType: hard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"has-flag@npm:^4.0.0":
 | 
					 | 
				
			||||||
  version: 4.0.0
 | 
					 | 
				
			||||||
  resolution: "has-flag@npm:4.0.0"
 | 
					 | 
				
			||||||
  checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad
 | 
					 | 
				
			||||||
  languageName: node
 | 
					 | 
				
			||||||
  linkType: hard
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"inflight@npm:^1.0.4":
 | 
					"inflight@npm:^1.0.4":
 | 
				
			||||||
  version: 1.0.6
 | 
					  version: 1.0.6
 | 
				
			||||||
  resolution: "inflight@npm:1.0.6"
 | 
					  resolution: "inflight@npm:1.0.6"
 | 
				
			||||||
@ -194,9 +131,9 @@ __metadata:
 | 
				
			|||||||
  version: 0.0.0-use.local
 | 
					  version: 0.0.0-use.local
 | 
				
			||||||
  resolution: "notion-enhancer@workspace:."
 | 
					  resolution: "notion-enhancer@workspace:."
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@electron/asar": ^3.2.2
 | 
					    "@electron/asar": ^3.2.4
 | 
				
			||||||
    arg: ^5.0.2
 | 
					    arg: ^5.0.2
 | 
				
			||||||
    chalk-template: ^0.4.0
 | 
					    chalk-template: ^1.0.0
 | 
				
			||||||
  bin:
 | 
					  bin:
 | 
				
			||||||
    notion-enhancer: bin.mjs
 | 
					    notion-enhancer: bin.mjs
 | 
				
			||||||
  languageName: unknown
 | 
					  languageName: unknown
 | 
				
			||||||
@ -218,15 +155,6 @@ __metadata:
 | 
				
			|||||||
  languageName: node
 | 
					  languageName: node
 | 
				
			||||||
  linkType: hard
 | 
					  linkType: hard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"supports-color@npm:^7.1.0":
 | 
					 | 
				
			||||||
  version: 7.2.0
 | 
					 | 
				
			||||||
  resolution: "supports-color@npm:7.2.0"
 | 
					 | 
				
			||||||
  dependencies:
 | 
					 | 
				
			||||||
    has-flag: ^4.0.0
 | 
					 | 
				
			||||||
  checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a
 | 
					 | 
				
			||||||
  languageName: node
 | 
					 | 
				
			||||||
  linkType: hard
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"wrappy@npm:1":
 | 
					"wrappy@npm:1":
 | 
				
			||||||
  version: 1.0.2
 | 
					  version: 1.0.2
 | 
				
			||||||
  resolution: "wrappy@npm:1.0.2"
 | 
					  resolution: "wrappy@npm:1.0.2"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user