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",
exports: ["presetUno"],
}),
...esmBundle({
name: "@unocss/preset-icons",
version: "0.58.5",
exports: ["presetIcons"],
}),
"@unocss-preflight-tailwind.css":
"https://esm.sh/@unocss/reset@0.58.5/tailwind.css",
"coloris.min.js":

View File

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

View File

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

View File

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

View File

@ -16,16 +16,21 @@ const isElectron = () => {
if (isElectron()) {
require("./api/system.js");
require("./api/registry.js");
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) => {
const __getApi = () => globalThis.__enhancerApi;
if (target === ".webpack/main/index") require("./worker.js");
else {
// expose globalThis.__enhancerApi to scripts
const { contextBridge } = require("electron"),
__getEnhancerApi = () => globalThis.__enhancerApi;
contextBridge.exposeInMainWorld("__getEnhancerApi", __getEnhancerApi);
const { contextBridge } = require("electron");
contextBridge.exposeInMainWorld("__getEnhancerApi", __getApi);
// load clientStyles, clientScripts
document.addEventListener("readystatechange", () => {
@ -44,7 +49,7 @@ if (isElectron()) {
for (let [scriptTarget, script] of mod.electronScripts ?? []) {
if (target !== scriptTarget) continue;
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),
IS_MENU = location.href.startsWith(enhancerUrl("core/menu/index.html")),
IS_TABS = /\/app\/\.webpack\/renderer\/(draggable_)?tabs\/index.html$/.test(location.href),
IS_ELECTRON = ['linux', 'win32', 'darwin'].includes(platform);
if (IS_TABS) globalThis.IS_TABS = true;
IS_ELECTRON = ['linux', 'win32', 'darwin'].includes(platform),
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 (!signedIn || !pageLoaded) return;
@ -42,16 +46,16 @@ export default (async () => {
await Promise.all([
IS_ELECTRON || import(enhancerUrl("common/registry.js")),
(IS_ELECTRON && IS_MENU) || import(enhancerUrl("api/state.js")),
import(enhancerUrl("api/interface.mjs")),
import(enhancerUrl("api/state.js")),
]);
globalThis.__enhancerApi.__isReady(globalThis.__enhancerApi);
const { getMods, isEnabled, modDatabase } = globalThis.__enhancerApi;
for (const mod of await getMods()) {
if (!(await isEnabled(mod.id))) continue;
const isTheme = mod._src.startsWith("themes/");
if (IS_MENU && !(mod._src === "core" || isTheme)) continue;
const isCore = mod._src === "core",
isTheme = mod._src.startsWith("themes/");
if (IS_MENU && !(isCore || isTheme)) continue;
// clientStyles
for (let stylesheet of mod.clientStyles ?? []) {
@ -65,10 +69,18 @@ export default (async () => {
if (IS_MENU || IS_TABS) continue;
const db = await modDatabase(mod.id);
for (let script of mod.clientScripts ?? []) {
script = await import(enhancerUrl(`${mod._src}/${script}`));
script.default(globalThis.__enhancerApi, db);
// execute mod scripts after core has
// 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 || 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 });
globalThis.__enhancerReady?.();