refactor: platform-agnostic modloading

This commit is contained in:
dragonwocky 2022-12-15 01:04:56 +11:00
parent d304f698a8
commit a81a4dda6f
Signed by: dragonwocky
GPG Key ID: 7998D08F7D7BD7A8
12 changed files with 120 additions and 191 deletions

View File

@ -145,7 +145,7 @@ const unpackApp = async () => {
// create package.json // create package.json
// prettier-ignore // prettier-ignore
const manifestPath = getResourcePath("app/node_modules/notion-enhancer/package.json"), const manifestPath = getResourcePath("app/node_modules/notion-enhancer/package.json"),
jsManifest = { ...manifest, main: "electron/init.js" }; jsManifest = { ...manifest, main: "electron/init.cjs" };
// remove cli-specific fields // remove cli-specific fields
delete jsManifest.bin; delete jsManifest.bin;
delete jsManifest.type; delete jsManifest.type;

View File

@ -44,7 +44,7 @@ const initDatabase = (namespace) => {
}); });
if (!namespace) return obj; if (!namespace) return obj;
let entries = Object.entries(obj); let entries = Object.entries(obj);
entries = entries.filter(([key]) => key.startsWith(`${namespace}__`)); entries = entries.filter(([key]) => key.startsWith(namespace));
return Object.fromEntries(entries); return Object.fromEntries(entries);
}, },
populate: async (obj) => { populate: async (obj) => {

View File

@ -1,37 +1,13 @@
/* /**
* notion-enhancer * notion-enhancer
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/) * (c) 2022 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";
(async () => { (async () => {
const enhancerApi = await import("./api.js"); await import("./api.js");
globalThis.__enhancerApi = enhancerApi; await import("../common/registry.js");
// const site = location.host.endsWith('.notion.site'), await import("../common/loader.js");
// page = location.pathname.split(/[/-]/g).reverse()[0].length === 32,
// whitelisted = ['/', '/onboarding'].includes(location.pathname),
// signedIn = localStorage['LRU:KeyValueStore2:current-user-id'];
// if (site || page || (whitelisted && signedIn)) {
// const api = await import(chrome.runtime.getURL('api/index.mjs')),
// { fs, registry, web } = api;
// for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
// for (const sheet of mod.css?.client || []) {
// web.loadStylesheet(`repo/${mod._dir}/${sheet}`);
// }
// for (let script of mod.js?.client || []) {
// script = await import(fs.localPath(`repo/${mod._dir}/${script}`));
// script.default(api, await registry.db(mod.id));
// }
// }
// const errors = await registry.errors();
// if (errors.length) {
// console.log('[notion-enhancer] registry errors:');
// console.table(errors);
// }
// }
})(); })();

View File

@ -4,40 +4,27 @@
* (https://notion-enhancer.github.io/) under the MIT license * (https://notion-enhancer.github.io/) under the MIT license
*/ */
'use strict'; "use strict";
function focusMenu() { function focusMenu() {
chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT }, (tabs) => { chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT }, (tabs) => {
const url = chrome.runtime.getURL('repo/menu/menu.html'), const url = chrome.runtime.getURL("repo/menu/menu.html"),
menu = tabs.find((tab) => tab.url.startsWith(url)); menu = tabs.find((tab) => tab.url.startsWith(url));
if (menu) { if (menu) {
chrome.tabs.highlight({ 'tabs': menu.index }); chrome.tabs.highlight({ tabs: menu.index });
} else chrome.tabs.create({ url }); } else chrome.tabs.create({ url });
}); });
} }
chrome.browserAction.onClicked.addListener(focusMenu); chrome.browserAction.onClicked.addListener(focusMenu);
function focusNotion() {
chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT }, (tabs) => {
const notion = tabs.find((tab) => {
const url = new URL(tab.url),
matches = url.host.endsWith('.notion.so') || url.host.endsWith('.notion.site');
return matches;
});
if (notion) {
chrome.tabs.highlight({ 'tabs': notion.index });
} else chrome.tabs.create({ url: 'https://notion.so/' });
});
}
function reload() { function reload() {
chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT }, (tabs) => { chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT }, (tabs) => {
const menu = chrome.runtime.getURL('repo/menu/menu.html'); const menu = chrome.runtime.getURL("repo/menu/menu.html");
tabs.forEach((tab) => { tabs.forEach((tab) => {
const url = new URL(tab.url), const url = new URL(tab.url),
matches = matches =
url.host.endsWith('.notion.so') || url.host.endsWith(".notion.so") ||
url.host.endsWith('.notion.site') || url.host.endsWith(".notion.site") ||
tab.url.startsWith(menu); tab.url.startsWith(menu);
if (matches) chrome.tabs.reload(tab.id); if (matches) chrome.tabs.reload(tab.id);
}); });
@ -46,13 +33,13 @@ function reload() {
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
switch (request.action) { switch (request.action) {
case 'focusMenu': case "focusMenu":
focusMenu(); focusMenu();
break; break;
case 'focusNotion': case "focusNotion":
focusNotion(); focusNotion();
break; break;
case 'reload': case "reload":
reload(); reload();
break; break;
} }

34
src/common/loader.js Normal file
View File

@ -0,0 +1,34 @@
/**
* notion-enhancer
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
"use strict";
(async () => {
const signedIn = localStorage["LRU:KeyValueStore2:current-user-id"],
pageLoaded = /(^\/$)|(-[0-9a-f]{32}$)/.test(location.pathname);
if (!signedIn || !pageLoaded) return;
const { getMods, getProfile, isEnabled, enhancerUrl, initDatabase } =
globalThis.__enhancerApi;
for (const mod of await getMods()) {
if (!(await isEnabled(mod.id))) continue;
// clientStyles
for (let stylesheet of mod.clientStyles ?? []) {
const $stylesheet = document.createElement("link");
$stylesheet.rel = "stylesheet";
$stylesheet.href = enhancerUrl(`${mod._src}/${stylesheet}`);
document.head.appendChild($stylesheet);
}
// clientScripts
for (let script of mod.clientScripts ?? []) {
const db = initDatabase([await getProfile(), mod.id]);
script = await import(enhancerUrl(`${mod._src}/${script}`));
script.default(globalThis.__enhancerApi, db);
}
}
})();

View File

@ -7,24 +7,21 @@
"use strict"; "use strict";
let _core, _mods; let _core, _mods;
const getCore = () => { const getCore = async () => {
_core ??= globalThis.__enhancerApi.readJson("/core/mod.json"); _core ??= await globalThis.__enhancerApi.readJson("core/mod.json");
_core._src = "core";
return _core; return _core;
}, },
getMods = async () => { getMods = async () => {
const { readJson } = globalThis.__enhancerApi; const { readJson } = globalThis.__enhancerApi;
_mods ??= await Promise.all([ // prettier-ignore
_mods ??= (await Promise.all([
getCore(), getCore(),
// prettier-ignore ...(await readJson("mods/registry.json")).map(async (modFolder) => {
...(await readJson("/mods/registry.json")).map(async (modFolder) => { const modManifest = await readJson(`mods/${modFolder}/mod.json`);
try { return {...modManifest, _src: `mods/${modFolder}` };
modFolder = `/mods/${modFolder}/mod.json`;
const modManifest = await readJson(modFolder);
modManifest._src = modFolder;
return modManifest;
} catch {}
}), }),
]).filter((mod) => mod); ]));
return _mods; return _mods;
}, },
getThemes = async () => { getThemes = async () => {
@ -51,8 +48,8 @@ const getProfile = async () => {
mod = (await getMods()).find((mod) => mod.id === id); mod = (await getMods()).find((mod) => mod.id === id);
if (mod.platforms && !mod.platforms.includes(platform)) return false; if (mod.platforms && !mod.platforms.includes(platform)) return false;
const { initDatabase } = globalThis.__enhancerApi, const { initDatabase } = globalThis.__enhancerApi,
enabledMods = await initDatabase([await getProfile(), "enabledMods"]); enabledMods = initDatabase([await getProfile(), "enabledMods"]);
return Boolean(enabledMods.get(id)); return Boolean(await enabledMods.get(id));
}; };
globalThis.__enhancerApi ??= {}; globalThis.__enhancerApi ??= {};

View File

@ -40,5 +40,5 @@
], ],
"clientStyles": [], "clientStyles": [],
"clientScripts": [], "clientScripts": [],
"electronScripts": {} "electronScripts": []
} }

View File

@ -14,7 +14,7 @@ const fs = require("fs"),
const notionRequire = (target) => require(`../../../${target}`), const notionRequire = (target) => require(`../../../${target}`),
notionPath = (target) => path.resolve(`${__dirname}/../../../${target}`); notionPath = (target) => path.resolve(`${__dirname}/../../../${target}`);
const enhancerRequire = (target) => require(`../${target}`), const enhancerRequire = (target) => require(`notion-enhancer/${target}`),
enhancerPath = (target) => path.resolve(`${__dirname}/../${target}`), enhancerPath = (target) => path.resolve(`${__dirname}/../${target}`),
enhancerUrl = (target) => enhancerUrl = (target) =>
`notion://www.notion.so/__notion-enhancer/${target}`, `notion://www.notion.so/__notion-enhancer/${target}`,
@ -52,22 +52,21 @@ const initDatabase = (namespace) => {
db = __db ?? sqlite(enhancerConfig), db = __db ?? sqlite(enhancerConfig),
init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} ( init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} (
key TEXT PRIMARY KEY, key TEXT PRIMARY KEY,
value TEXT, value TEXT
mtime INTEGER
)`); )`);
init.run(); init.run();
__db = db; __db = db;
// prettier-ignore // prettier-ignore
const insert = db.prepare(`INSERT INTO ${table} (key, value, mtime) VALUES (?, ?, ?)`), const insert = db.prepare(`INSERT INTO ${table} (key, value) VALUES (?, ?)`),
// prettier-ignore // prettier-ignore
update = db.prepare(`UPDATE ${table} SET value = ?, mtime = ? WHERE key = ?`), update = db.prepare(`UPDATE ${table} SET value = ? WHERE key = ?`),
select = db.prepare(`SELECT * FROM ${table} WHERE key = ? LIMIT 1`), select = db.prepare(`SELECT * FROM ${table} WHERE key = ? LIMIT 1`),
dump = db.prepare(`SELECT * FROM ${table}`), dump = db.prepare(`SELECT * FROM ${table}`),
populate = db.transaction((obj) => { populate = db.transaction((obj) => {
for (const key in obj) { for (const key in obj) {
if (select.get(key)) update.run(value, key, Date.now()); if (select.get(key)) update.run(value, key);
else insert.run(key, value, Date.now()); else insert.run(key, value);
} }
}); });
@ -78,14 +77,15 @@ const initDatabase = (namespace) => {
}, },
set: (key, value) => { set: (key, value) => {
key = key.startsWith(namespace) ? key : namespace + key; key = key.startsWith(namespace) ? key : namespace + key;
if (select.get(key)) return update.run(value, key, Date.now()); return select.get(key) === undefined
else return insert.run(key, value, Date.now()); ? insert.run(key, value)
: update.run(value, key);
}, },
dump: () => { dump: () => {
const rows = dump.all(); const entries = dump
let entries = rows.map(({ key, value }) => [key, value]); .all()
if (!namespace) return Object.fromEntries(entries); .map(({ key, value }) => [key, value])
entries = entries.filter(([key]) => key.startsWith(`${namespace}__`)); .filter(([key]) => key.startsWith(namespace));
return Object.fromEntries(entries); return Object.fromEntries(entries);
}, },
populate, populate,

View File

@ -1,35 +0,0 @@
/**
* notion-enhancer
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
"use strict";
console.log(123);
(async () => {
// const { getCore, getMods, enhancerPath } = globalThis.__enhancerApi;
// console.log(await getMods());
// const page = location.pathname.split(/[/-]/g).reverse()[0].length === 32,
// whitelisted = ["/", "/onboarding"].includes(location.pathname),
// signedIn = localStorage["LRU:KeyValueStore2:current-user-id"];
// if (page || (whitelisted && signedIn)) {
// const api = await import("./api/index.mjs"),
// { fs, registry, web } = api;
// for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
// for (const sheet of mod.css?.client || []) {
// web.loadStylesheet(`repo/${mod._dir}/${sheet}`);
// }
// for (let script of mod.js?.client || []) {
// script = await import(fs.localPath(`repo/${mod._dir}/${script}`));
// script.default(api, await registry.db(mod.id));
// }
// }
// const errors = await registry.errors();
// if (errors.length) {
// console.error("[notion-enhancer] registry errors:");
// console.table(errors);
// }
// }
})();

View File

@ -6,30 +6,37 @@
"use strict"; "use strict";
require("./api"); require("./api.cjs");
require("../common/registry.js"); require("../common/registry.js");
module.exports = async (target, __exports, __eval) => { module.exports = async (target, __exports, __eval) => {
const {
getMods,
getProfile,
isEnabled,
enhancerRequire,
enhancerUrl,
initDatabase,
} = globalThis.__enhancerApi;
// clientScripts // clientScripts
if (target === "renderer/preload") { if (target === "renderer/preload") {
const { enhancerUrl } = globalThis.__enhancerApi;
document.addEventListener("readystatechange", (event) => { document.addEventListener("readystatechange", (event) => {
if (document.readyState !== "complete") return false; if (document.readyState !== "complete") return false;
const script = document.createElement("script"); const $script = document.createElement("script");
script.type = "module"; $script.type = "module";
script.src = enhancerUrl("electron/client.js"); $script.src = enhancerUrl("common/loader.js");
document.head.appendChild(script); document.head.appendChild($script);
}); });
} }
// electronScripts // electronScripts
const { getMods, getProfile, initDatabase } = globalThis.__enhancerApi;
for (const mod of await getMods()) { for (const mod of await getMods()) {
if (!mod.electronScripts || !isEnabled(mod.id)) continue; if (!mod.electronScripts || !(await isEnabled(mod.id))) continue;
for (const { source, target: targetScript } of mod.electronScripts) { for (const { source, target: targetScript } of mod.electronScripts) {
if (`${target}.js` !== targetScript) continue; if (`${target}.js` !== targetScript) continue;
const script = require(`notion-enhancer/repo/${mod._dir}/${source}`), const script = enhancerRequire(`${mod._src}/${source}`),
db = await initDatabase([await getProfile(), mod.id]); db = initDatabase([await getProfile(), mod.id]);
script(globalThis.__enhancerApi, db, __exports, __eval); script(globalThis.__enhancerApi, db, __exports, __eval);
} }
} }

View File

@ -1,30 +1,39 @@
{ {
"manifest_version": 2, "manifest_version": 3,
"name": "notion-enhancer", "name": "notion-enhancer",
"version": "0.11.0", "version": "0.11.1",
"author": "dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)", "author": "dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)",
"description": "an enhancer/customiser for the all-in-one productivity workspace notion.so", "description": "an enhancer/customiser for the all-in-one productivity workspace notion.so",
"homepage_url": "https://notion-enhancer.github.io", "homepage_url": "https://notion-enhancer.github.io",
"icons": { "icons": {
"16": "media/colour-x16.png", "16": "/media/colour-x16.png",
"32": "media/colour-x32.png", "32": "/media/colour-x32.png",
"48": "media/colour-x48.png", "48": "/media/colour-x48.png",
"128": "media/colour-x128.png", "128": "/media/colour-x128.png",
"256": "media/colour-x256.png", "256": "/media/colour-x256.png",
"512": "media/colour-x512.png" "512": "/media/colour-x512.png"
}, },
"browser_action": {}, "action": {},
"background": { "scripts": ["worker.js"] }, "background": { "service_worker": "/browser/worker.js" },
"options_ui": { "options_page": "/core/menu.html",
"page": "mods/menu/menu.html",
"open_in_tab": true
},
"web_accessible_resources": ["browser/*", "common/*", "vendor/*", "media/*", "mods/*"],
"content_scripts": [ "content_scripts": [
{ {
"matches": ["https://*.notion.so/*", "https://*.notion.site/*"], "matches": ["*://*.notion.so/*", "https://*.notion.site/*"],
"js": ["browser/init.js"] "js": ["/browser/init.js"]
} }
], ],
"permissions": ["tabs", "storage", "clipboardRead", "clipboardWrite", "unlimitedStorage"] "web_accessible_resources": [
{
"matches": ["*://*.notion.so/*", "https://*.notion.site/*"],
"resources": ["/*"]
}
],
"permissions": [
"tabs",
"storage",
"clipboardRead",
"clipboardWrite",
"unlimitedStorage"
],
"host_permissions": ["*://*.notion.so/*", "*://*.notion.site/*"]
} }

View File

@ -1,47 +1 @@
[ []
"menu",
"theming",
"components",
"tweaks",
"font-chooser",
"integrated-titlebar",
"tray",
"tabs",
"always-on-top",
"view-scale",
"outliner",
"scroll-to-top",
"indentation-lines",
"right-to-left",
"simpler-databases",
"emoji-sets",
"bypass-preview",
"topbar-icons",
"word-counter",
"code-line-numbers",
"calendar-scroll",
"collapsible-properties",
"weekly-view",
"truncated-titles",
"focus-mode",
"global-block-links",
"icon-sets",
"quick-note",
"material-ocean",
"cherry-cola",
"dark+",
"light+",
"dracula",
"pastel-dark",
"neutral",
"nord",
"gruvbox-dark",
"gruvbox-light",
"playful-purple",
"pinky-boom"
]