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
// prettier-ignore
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
delete jsManifest.bin;
delete jsManifest.type;

View File

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

View File

@ -1,37 +1,13 @@
/*
/**
* 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
*/
"use strict";
(async () => {
const enhancerApi = await import("./api.js");
globalThis.__enhancerApi = enhancerApi;
// const site = location.host.endsWith('.notion.site'),
// 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);
// }
// }
await import("./api.js");
await import("../common/registry.js");
await import("../common/loader.js");
})();

View File

@ -4,40 +4,27 @@
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
"use strict";
function focusMenu() {
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));
if (menu) {
chrome.tabs.highlight({ 'tabs': menu.index });
chrome.tabs.highlight({ tabs: menu.index });
} else chrome.tabs.create({ url });
});
}
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() {
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) => {
const url = new URL(tab.url),
matches =
url.host.endsWith('.notion.so') ||
url.host.endsWith('.notion.site') ||
url.host.endsWith(".notion.so") ||
url.host.endsWith(".notion.site") ||
tab.url.startsWith(menu);
if (matches) chrome.tabs.reload(tab.id);
});
@ -46,13 +33,13 @@ function reload() {
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
switch (request.action) {
case 'focusMenu':
case "focusMenu":
focusMenu();
break;
case 'focusNotion':
case "focusNotion":
focusNotion();
break;
case 'reload':
case "reload":
reload();
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";
let _core, _mods;
const getCore = () => {
_core ??= globalThis.__enhancerApi.readJson("/core/mod.json");
const getCore = async () => {
_core ??= await globalThis.__enhancerApi.readJson("core/mod.json");
_core._src = "core";
return _core;
},
getMods = async () => {
const { readJson } = globalThis.__enhancerApi;
_mods ??= await Promise.all([
// prettier-ignore
_mods ??= (await Promise.all([
getCore(),
// prettier-ignore
...(await readJson("/mods/registry.json")).map(async (modFolder) => {
try {
modFolder = `/mods/${modFolder}/mod.json`;
const modManifest = await readJson(modFolder);
modManifest._src = modFolder;
return modManifest;
} catch {}
...(await readJson("mods/registry.json")).map(async (modFolder) => {
const modManifest = await readJson(`mods/${modFolder}/mod.json`);
return {...modManifest, _src: `mods/${modFolder}` };
}),
]).filter((mod) => mod);
]));
return _mods;
},
getThemes = async () => {
@ -51,8 +48,8 @@ const getProfile = async () => {
mod = (await getMods()).find((mod) => mod.id === id);
if (mod.platforms && !mod.platforms.includes(platform)) return false;
const { initDatabase } = globalThis.__enhancerApi,
enabledMods = await initDatabase([await getProfile(), "enabledMods"]);
return Boolean(enabledMods.get(id));
enabledMods = initDatabase([await getProfile(), "enabledMods"]);
return Boolean(await enabledMods.get(id));
};
globalThis.__enhancerApi ??= {};

View File

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

View File

@ -14,7 +14,7 @@ const fs = require("fs"),
const notionRequire = (target) => require(`../../../${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}`),
enhancerUrl = (target) =>
`notion://www.notion.so/__notion-enhancer/${target}`,
@ -52,22 +52,21 @@ const initDatabase = (namespace) => {
db = __db ?? sqlite(enhancerConfig),
init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} (
key TEXT PRIMARY KEY,
value TEXT,
mtime INTEGER
value TEXT
)`);
init.run();
__db = db;
// 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
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`),
dump = db.prepare(`SELECT * FROM ${table}`),
populate = db.transaction((obj) => {
for (const key in obj) {
if (select.get(key)) update.run(value, key, Date.now());
else insert.run(key, value, Date.now());
if (select.get(key)) update.run(value, key);
else insert.run(key, value);
}
});
@ -78,14 +77,15 @@ const initDatabase = (namespace) => {
},
set: (key, value) => {
key = key.startsWith(namespace) ? key : namespace + key;
if (select.get(key)) return update.run(value, key, Date.now());
else return insert.run(key, value, Date.now());
return select.get(key) === undefined
? insert.run(key, value)
: update.run(value, key);
},
dump: () => {
const rows = dump.all();
let entries = rows.map(({ key, value }) => [key, value]);
if (!namespace) return Object.fromEntries(entries);
entries = entries.filter(([key]) => key.startsWith(`${namespace}__`));
const entries = dump
.all()
.map(({ key, value }) => [key, value])
.filter(([key]) => key.startsWith(namespace));
return Object.fromEntries(entries);
},
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";
require("./api");
require("./api.cjs");
require("../common/registry.js");
module.exports = async (target, __exports, __eval) => {
const {
getMods,
getProfile,
isEnabled,
enhancerRequire,
enhancerUrl,
initDatabase,
} = globalThis.__enhancerApi;
// clientScripts
if (target === "renderer/preload") {
const { enhancerUrl } = globalThis.__enhancerApi;
document.addEventListener("readystatechange", (event) => {
if (document.readyState !== "complete") return false;
const script = document.createElement("script");
script.type = "module";
script.src = enhancerUrl("electron/client.js");
document.head.appendChild(script);
const $script = document.createElement("script");
$script.type = "module";
$script.src = enhancerUrl("common/loader.js");
document.head.appendChild($script);
});
}
// electronScripts
const { getMods, getProfile, initDatabase } = globalThis.__enhancerApi;
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) {
if (`${target}.js` !== targetScript) continue;
const script = require(`notion-enhancer/repo/${mod._dir}/${source}`),
db = await initDatabase([await getProfile(), mod.id]);
const script = enhancerRequire(`${mod._src}/${source}`),
db = initDatabase([await getProfile(), mod.id]);
script(globalThis.__enhancerApi, db, __exports, __eval);
}
}

View File

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