chore: ensure api is loaded before mod scripts execute

This commit is contained in:
dragonwocky 2024-02-19 14:11:37 +11:00
parent 1f717b98ca
commit ef09280f61
Signed by: dragonwocky
GPG Key ID: 7998D08F7D7BD7A8
8 changed files with 42 additions and 61 deletions

View File

@ -37,11 +37,6 @@ const dependencies = {
version: "0.58.5", version: "0.58.5",
exports: ["presetUno"], exports: ["presetUno"],
}), }),
...esmBundle({
name: "@unocss/preset-icons",
version: "0.58.5",
exports: ["presetIcons"],
}),
"@unocss-preflight-tailwind.css": "@unocss-preflight-tailwind.css":
"https://esm.sh/@unocss/reset@0.58.5/tailwind.css", "https://esm.sh/@unocss/reset@0.58.5/tailwind.css",
"coloris.min.js": "coloris.min.js":

View File

@ -37,29 +37,29 @@ const sleep = async (ms) => {
// supports inter-mod communication if so // supports inter-mod communication if so
// required. caution should be used in // required. caution should be used in
// naming keys to avoid conflicts // naming keys to avoid conflicts
const _state = {}, const _subscribers = [],
_subscribers = [], dumpState = () => (document.__enhancerState ??= {}),
getKeysFromState = (keys) => keys.map((key) => dumpState()[key]),
setState = (state) => { setState = (state) => {
Object.assign(_state, state); Object.assign(dumpState(), state);
const updates = Object.keys(state); const updates = Object.keys(state);
_subscribers _subscribers
.filter(([keys]) => updates.some((key) => keys.includes(key))) .filter(([keys]) => updates.some((key) => keys.includes(key)))
.forEach(([keys, callback]) => callback(keys.map((key) => _state[key]))); .forEach(([keys, callback]) => callback(getKeysFromState(keys)));
}, },
// useState(["keyA", "keyB"]) => returns [valueA, valueB] // useState(["keyA", "keyB"]) => returns [valueA, valueB]
// useState(["keyA", "keyB"], callback) => registers callback // useState(["keyA", "keyB"], callback) => registers callback
// to be triggered after each update to either keyA or keyB, // to be triggered after each update to either keyA or keyB,
// with [valueA, valueB] passed to the callback's first arg // with [valueA, valueB] passed to the callback's first arg
useState = (keys, callback) => { useState = (keys, callback) => {
const state = keys.map((key) => _state[key]); const state = getKeysFromState(keys);
if (callback) { if (callback) {
callback = debounce(callback); callback = debounce(callback);
_subscribers.push([keys, callback]); _subscribers.push([keys, callback]);
callback(state); callback(state);
} }
return state; return state;
}, };
dumpState = () => _state;
Object.assign((globalThis.__enhancerApi ??= {}), { Object.assign((globalThis.__enhancerApi ??= {}), {
sleep, sleep,

View File

@ -7,11 +7,7 @@
"use strict"; "use strict";
const IS_ELECTRON = typeof module !== "undefined", const IS_ELECTRON = typeof module !== "undefined",
IS_RENDERER = IS_ELECTRON && process.type === "renderer", IS_RENDERER = IS_ELECTRON && process.type === "renderer";
API_LOADED = new Promise((res, rej) => {
(globalThis.__enhancerApi ??= {}).__isReady = res;
}),
whenReady = (callback) => API_LOADED.then(callback);
// expected values: 'linux', 'win32', 'darwin' (== macos), 'firefox' // expected values: 'linux', 'win32', 'darwin' (== macos), 'firefox'
// and 'chromium' (inc. chromium-based browsers like edge and brave) // and 'chromium' (inc. chromium-based browsers like edge and brave)
@ -160,5 +156,4 @@ Object.assign((globalThis.__enhancerApi ??= {}), {
readJson, readJson,
initDatabase, initDatabase,
reloadApp, reloadApp,
whenReady,
}); });

View File

@ -6,9 +6,8 @@
"use strict"; "use strict";
module.exports = async ({ whenReady }, db) => { module.exports = async (api, db) => {
const api = await whenReady(), const { html, addMutationListener } = api,
{ html, addMutationListener } = api,
{ enhancerUrl, onMessage, sendMessage } = api, { enhancerUrl, onMessage, sendMessage } = api,
titlebarStyle = await db.get("titlebarStyle"); titlebarStyle = await db.get("titlebarStyle");

View File

@ -16,16 +16,21 @@ const isElectron = () => {
if (isElectron()) { if (isElectron()) {
require("./api/system.js"); require("./api/system.js");
require("./api/registry.js"); require("./api/registry.js");
const { enhancerUrl } = globalThis.__enhancerApi, const { enhancerUrl } = globalThis.__enhancerApi,
{ getMods, isEnabled, modDatabase } = globalThis.__enhancerApi; { getMods, isEnabled, modDatabase } = globalThis.__enhancerApi,
API_LOADED = new Promise((res, rej) => {
const onReady = globalThis.__enhancerReady;
globalThis.__enhancerReady = () => (onReady?.(), res());
});
module.exports = async (target, __exports, __eval) => { module.exports = async (target, __exports, __eval) => {
const __getApi = () => globalThis.__enhancerApi;
if (target === ".webpack/main/index") require("./worker.js"); if (target === ".webpack/main/index") require("./worker.js");
else { else {
// expose globalThis.__enhancerApi to scripts // expose globalThis.__enhancerApi to scripts
const { contextBridge } = require("electron"), const { contextBridge } = require("electron");
__getEnhancerApi = () => globalThis.__enhancerApi; contextBridge.exposeInMainWorld("__getEnhancerApi", __getApi);
contextBridge.exposeInMainWorld("__getEnhancerApi", __getEnhancerApi);
// load clientStyles, clientScripts // load clientStyles, clientScripts
document.addEventListener("readystatechange", () => { document.addEventListener("readystatechange", () => {
@ -44,7 +49,7 @@ if (isElectron()) {
for (let [scriptTarget, script] of mod.electronScripts ?? []) { for (let [scriptTarget, script] of mod.electronScripts ?? []) {
if (target !== scriptTarget) continue; if (target !== scriptTarget) continue;
script = require(`./${mod._src}/${script}`); script = require(`./${mod._src}/${script}`);
script(globalThis.__enhancerApi, db, __exports, __eval); API_LOADED.then(() => script(__getApi(), db, __exports, __eval));
} }
} }
}; };

View File

@ -17,8 +17,12 @@ export default (async () => {
pageLoaded = /(^\/$)|((-|\/)[0-9a-f]{32}((\?.+)|$))/.test(location.pathname), pageLoaded = /(^\/$)|((-|\/)[0-9a-f]{32}((\?.+)|$))/.test(location.pathname),
IS_MENU = location.href.startsWith(enhancerUrl("core/menu/index.html")), IS_MENU = location.href.startsWith(enhancerUrl("core/menu/index.html")),
IS_TABS = /\/app\/\.webpack\/renderer\/(draggable_)?tabs\/index.html$/.test(location.href), IS_TABS = /\/app\/\.webpack\/renderer\/(draggable_)?tabs\/index.html$/.test(location.href),
IS_ELECTRON = ['linux', 'win32', 'darwin'].includes(platform); IS_ELECTRON = ['linux', 'win32', 'darwin'].includes(platform),
if (IS_TABS) globalThis.IS_TABS = true; API_LOADED = new Promise((res, rej) => {
const onReady = globalThis.__enhancerReady;
globalThis.__enhancerReady = () => (onReady?.(), res());
});
globalThis.IS_TABS = IS_TABS;
if (!IS_MENU && !IS_TABS) { if (!IS_MENU && !IS_TABS) {
if (!signedIn || !pageLoaded) return; if (!signedIn || !pageLoaded) return;
@ -42,16 +46,16 @@ export default (async () => {
await Promise.all([ await Promise.all([
IS_ELECTRON || import(enhancerUrl("common/registry.js")), IS_ELECTRON || import(enhancerUrl("common/registry.js")),
(IS_ELECTRON && IS_MENU) || import(enhancerUrl("api/state.js")),
import(enhancerUrl("api/interface.mjs")), import(enhancerUrl("api/interface.mjs")),
import(enhancerUrl("api/state.js")),
]); ]);
globalThis.__enhancerApi.__isReady(globalThis.__enhancerApi);
const { getMods, isEnabled, modDatabase } = globalThis.__enhancerApi; const { getMods, isEnabled, modDatabase } = globalThis.__enhancerApi;
for (const mod of await getMods()) { for (const mod of await getMods()) {
if (!(await isEnabled(mod.id))) continue; if (!(await isEnabled(mod.id))) continue;
const isTheme = mod._src.startsWith("themes/"); const isCore = mod._src === "core",
if (IS_MENU && !(mod._src === "core" || isTheme)) continue; isTheme = mod._src.startsWith("themes/");
if (IS_MENU && !(isCore || isTheme)) continue;
// clientStyles // clientStyles
for (let stylesheet of mod.clientStyles ?? []) { for (let stylesheet of mod.clientStyles ?? []) {
@ -65,10 +69,18 @@ export default (async () => {
if (IS_MENU || IS_TABS) continue; if (IS_MENU || IS_TABS) continue;
const db = await modDatabase(mod.id); const db = await modDatabase(mod.id);
for (let script of mod.clientScripts ?? []) { for (let script of mod.clientScripts ?? []) {
script = await import(enhancerUrl(`${mod._src}/${script}`)); // execute mod scripts after core has
script.default(globalThis.__enhancerApi, db); // loaded and api is ready to use
Promise.resolve(isCore || API_LOADED)
.then(() => import(enhancerUrl(`${mod._src}/${script}`)))
.then((script) => script.default(globalThis.__enhancerApi, db))
.then(() => !isCore || globalThis.__enhancerReady?.());
} }
} }
if (IS_MENU) console.log("notion-enhancer: ready"); if (IS_MENU || IS_TABS) globalThis.__enhancerReady?.();
return API_LOADED.then(() => {
if (IS_MENU) console.log("notion-enhancer: ready");
return globalThis.__enhancerApi;
});
})(); })();

File diff suppressed because one or more lines are too long

View File

@ -176,3 +176,4 @@ if (IS_ELECTRON) {
} }
Object.assign((globalThis.__enhancerApi ??= {}), { queryDatabase }); Object.assign((globalThis.__enhancerApi ??= {}), { queryDatabase });
globalThis.__enhancerReady?.();