mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-12 00:09:03 +00:00
feat(desktop): use sqlite3 db
should fix the occasional db resets on concurrent read/write ops experienced with the json db
This commit is contained in:
parent
73e3c7c3a9
commit
44702af188
31
bin.mjs
31
bin.mjs
@ -13,14 +13,14 @@ import { createRequire } from "node:module";
|
|||||||
import {
|
import {
|
||||||
getAppPath,
|
getAppPath,
|
||||||
getBackupPath,
|
getBackupPath,
|
||||||
getCachePath,
|
getConfigPath,
|
||||||
checkEnhancementVersion,
|
checkEnhancementVersion,
|
||||||
setNotionPath,
|
setNotionPath,
|
||||||
unpackApp,
|
unpackApp,
|
||||||
applyEnhancements,
|
applyEnhancements,
|
||||||
takeBackup,
|
takeBackup,
|
||||||
restoreBackup,
|
restoreBackup,
|
||||||
removeCache,
|
removeConfig,
|
||||||
} from "./scripts/enhance-desktop-app.mjs";
|
} from "./scripts/enhance-desktop-app.mjs";
|
||||||
import { existsSync } from "node:fs";
|
import { existsSync } from "node:fs";
|
||||||
const nodeRequire = createRequire(import.meta.url),
|
const nodeRequire = createRequire(import.meta.url),
|
||||||
@ -201,7 +201,7 @@ try {
|
|||||||
|
|
||||||
const appPath = getAppPath(),
|
const appPath = getAppPath(),
|
||||||
backupPath = getBackupPath(),
|
backupPath = getBackupPath(),
|
||||||
cachePath = getCachePath(),
|
configPath = getConfigPath(),
|
||||||
insertVersion = checkEnhancementVersion();
|
insertVersion = checkEnhancementVersion();
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
@ -223,9 +223,9 @@ try {
|
|||||||
then install a vanilla version of the app from https://www.notion.so/desktop (mac,
|
then install a vanilla version of the app from https://www.notion.so/desktop (mac,
|
||||||
windows) or ${manifest.homepage}/getting-started/installation (linux)`,
|
windows) or ${manifest.homepage}/getting-started/installation (linux)`,
|
||||||
|
|
||||||
"cache-found": `cache found`,
|
"config-found": `config found`,
|
||||||
"cache-not-found": `cache not found: nothing to remove`,
|
"config-not-found": `config not found: nothing to remove`,
|
||||||
"prompt-cache-removal": `remove?`,
|
"prompt-config-removal": `remove?`,
|
||||||
};
|
};
|
||||||
const SUCCESS = chalk`{bold.whiteBright SUCCESS} {green ✔}`,
|
const SUCCESS = chalk`{bold.whiteBright SUCCESS} {green ✔}`,
|
||||||
FAILURE = chalk`{bold.whiteBright FAILURE} {red ✘}`,
|
FAILURE = chalk`{bold.whiteBright FAILURE} {red ✘}`,
|
||||||
@ -309,17 +309,16 @@ try {
|
|||||||
print` {grey * ${messages["notion-found"]}: ${messages["not-applied"]}}\n`;
|
print` {grey * ${messages["notion-found"]}: ${messages["not-applied"]}}\n`;
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
},
|
},
|
||||||
promptCacheRemoval = async () => {
|
promptConfigRemoval = async () => {
|
||||||
// optionally remove ~/.notion-enhancer
|
if (existsSync(configPath)) {
|
||||||
if (existsSync(cachePath)) {
|
print` {grey * ${messages["config-found"]}: ${configPath}}\n`;
|
||||||
print` {grey * ${messages["cache-found"]}: ${cachePath}}\n`;
|
if (["Y", "y"].includes(await promptConfirmation(messages["prompt-config-removal"]))) {
|
||||||
if (["Y", "y"].includes(await promptConfirmation(messages["prompt-cache-removal"]))) {
|
|
||||||
print` `;
|
print` `;
|
||||||
startSpinner();
|
startSpinner();
|
||||||
await removeCache();
|
await removeConfig();
|
||||||
stopSpinner();
|
stopSpinner();
|
||||||
} else print`\n`;
|
} else print`\n`;
|
||||||
} else print` {grey * ${messages["cache-not-found"]}}\n`;
|
} else print` {grey * ${messages["config-not-found"]}}\n`;
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (args["_"][0]) {
|
switch (args["_"][0]) {
|
||||||
@ -333,7 +332,7 @@ try {
|
|||||||
case "remove": {
|
case "remove": {
|
||||||
print`{bold.whiteBright [NOTION-ENHANCER] REMOVE}\n`;
|
print`{bold.whiteBright [NOTION-ENHANCER] REMOVE}\n`;
|
||||||
const res = await interactiveRemoveEnhancements();
|
const res = await interactiveRemoveEnhancements();
|
||||||
await promptCacheRemoval();
|
await promptConfigRemoval();
|
||||||
print`${res}\n`;
|
print`${res}\n`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -342,8 +341,8 @@ try {
|
|||||||
printObject({
|
printObject({
|
||||||
appPath,
|
appPath,
|
||||||
backupPath,
|
backupPath,
|
||||||
cachePath,
|
configPath,
|
||||||
cacheExists: existsSync(cachePath),
|
configExists: existsSync(configPath),
|
||||||
insertVersion,
|
insertVersion,
|
||||||
currentVersion: manifest.version,
|
currentVersion: manifest.version,
|
||||||
});
|
});
|
||||||
|
@ -15,7 +15,7 @@ import { createRequire } from "node:module";
|
|||||||
|
|
||||||
import patch from "./patch-desktop-app.mjs";
|
import patch from "./patch-desktop-app.mjs";
|
||||||
|
|
||||||
let __notionResources, __enhancerCache;
|
let __notionResources, __enhancerConfig;
|
||||||
const nodeRequire = createRequire(import.meta.url),
|
const nodeRequire = createRequire(import.meta.url),
|
||||||
manifest = nodeRequire("../package.json"),
|
manifest = nodeRequire("../package.json"),
|
||||||
platform =
|
platform =
|
||||||
@ -89,11 +89,11 @@ const setNotionPath = (path) => {
|
|||||||
// prefer unpacked if both exist
|
// prefer unpacked if both exist
|
||||||
getAppPath = () => ["app", "app.asar"].map(getResourcePath).find(existsSync),
|
getAppPath = () => ["app", "app.asar"].map(getResourcePath).find(existsSync),
|
||||||
getBackupPath = () => ["app.bak", "app.asar.bak"].map(getResourcePath).find(existsSync),
|
getBackupPath = () => ["app.bak", "app.asar.bak"].map(getResourcePath).find(existsSync),
|
||||||
getCachePath = () => {
|
getConfigPath = () => {
|
||||||
if (__enhancerCache) return __enhancerCache;
|
if (__enhancerConfig) return __enhancerConfig;
|
||||||
const home = platform === "wsl" ? polyfillWslEnv("HOMEPATH") : os.homedir();
|
const home = platform === "wsl" ? polyfillWslEnv("HOMEPATH") : os.homedir();
|
||||||
__enhancerCache = resolve(`${home}/.notion-enhancer`);
|
__enhancerConfig = resolve(`${home}/.notion-enhancer.db`);
|
||||||
return __enhancerCache;
|
return __enhancerConfig;
|
||||||
},
|
},
|
||||||
checkEnhancementVersion = () => {
|
checkEnhancementVersion = () => {
|
||||||
const manifestPath = getResourcePath("app/node_modules/notion-enhancer/package.json");
|
const manifestPath = getResourcePath("app/node_modules/notion-enhancer/package.json");
|
||||||
@ -172,9 +172,9 @@ const unpackApp = async () => {
|
|||||||
if (destPath !== appPath) await fsp.rm(appPath, { recursive: true });
|
if (destPath !== appPath) await fsp.rm(appPath, { recursive: true });
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
removeCache = async () => {
|
removeConfig = async () => {
|
||||||
if (!existsSync(getCachePath())) return;
|
if (!existsSync(getConfigPath())) return;
|
||||||
await fsp.rm(getCachePath());
|
await fsp.rm(getConfigPath());
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -182,12 +182,12 @@ export {
|
|||||||
getResourcePath,
|
getResourcePath,
|
||||||
getAppPath,
|
getAppPath,
|
||||||
getBackupPath,
|
getBackupPath,
|
||||||
getCachePath,
|
getConfigPath,
|
||||||
checkEnhancementVersion,
|
checkEnhancementVersion,
|
||||||
setNotionPath,
|
setNotionPath,
|
||||||
unpackApp,
|
unpackApp,
|
||||||
applyEnhancements,
|
applyEnhancements,
|
||||||
takeBackup,
|
takeBackup,
|
||||||
restoreBackup,
|
restoreBackup,
|
||||||
removeCache,
|
removeConfig,
|
||||||
};
|
};
|
||||||
|
@ -1,169 +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';
|
|
||||||
|
|
||||||
const os = require('os'),
|
|
||||||
path = require('path'),
|
|
||||||
fs = require('fs'),
|
|
||||||
_cacheFile = path.resolve(`${os.homedir()}/.notion-enhancer`),
|
|
||||||
_fsQueue = new Set(),
|
|
||||||
_onDbChangeListeners = [];
|
|
||||||
|
|
||||||
// handle leftover cache from prev versions
|
|
||||||
if (fs.existsSync(_cacheFile) && fs.lstatSync(_cacheFile).isDirectory()) {
|
|
||||||
fs.rmdirSync(_cacheFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isRenderer = process && process.type === 'renderer';
|
|
||||||
|
|
||||||
// things are a little weird here:
|
|
||||||
// multiple processes performing file ops at once
|
|
||||||
// (e.g. when too many windows/tabs are open)
|
|
||||||
// = an empty string is returned the cache contents
|
|
||||||
// and the db is reset. this loop roughly addresses that.
|
|
||||||
|
|
||||||
// a "real" db might be better, but sql or query-based
|
|
||||||
// would be incompatible with the chrome ext.
|
|
||||||
// -- lowdb might have been a nice flat/json db,
|
|
||||||
// but unfortunately it is esm only
|
|
||||||
|
|
||||||
const getData = async () => {
|
|
||||||
if (!fs.existsSync(_cacheFile)) {
|
|
||||||
fs.writeFileSync(_cacheFile, '{}', 'utf8');
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
let cacheBuffer = '',
|
|
||||||
jsonData = {},
|
|
||||||
attemptsRemaining = 3;
|
|
||||||
while (attemptsRemaining) {
|
|
||||||
cacheBuffer = fs.readFileSync(_cacheFile);
|
|
||||||
if (cacheBuffer) {
|
|
||||||
try {
|
|
||||||
jsonData = JSON.parse(cacheBuffer);
|
|
||||||
break;
|
|
||||||
} catch {
|
|
||||||
jsonData = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
--attemptsRemaining || (await new Promise((res, rej) => setTimeout(res, 50)));
|
|
||||||
}
|
|
||||||
return jsonData;
|
|
||||||
},
|
|
||||||
saveData = (data) => fs.writeFileSync(_cacheFile, JSON.stringify(data)),
|
|
||||||
performFsOperation = async (callback) => {
|
|
||||||
while (_fsQueue.size) await new Promise(requestIdleCallback);
|
|
||||||
const op = Symbol();
|
|
||||||
_fsQueue.add(op);
|
|
||||||
const res = await callback();
|
|
||||||
_fsQueue.delete(op);
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
const db = {
|
|
||||||
get: async (path, fallback = undefined) => {
|
|
||||||
if (!path.length) return fallback;
|
|
||||||
while (_fsQueue.size) await new Promise(requestIdleCallback);
|
|
||||||
const values = await getData();
|
|
||||||
let value = values;
|
|
||||||
while (path.length) {
|
|
||||||
if (value === undefined) {
|
|
||||||
value = fallback;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
value = value[path.shift()];
|
|
||||||
}
|
|
||||||
return value ?? fallback;
|
|
||||||
},
|
|
||||||
set: async (path, value) => {
|
|
||||||
if (!path.length) return undefined;
|
|
||||||
return await performFsOperation(async () => {
|
|
||||||
const pathClone = [...path],
|
|
||||||
values = await getData();
|
|
||||||
let pointer = values,
|
|
||||||
old;
|
|
||||||
while (path.length) {
|
|
||||||
const key = path.shift();
|
|
||||||
if (!path.length) {
|
|
||||||
old = pointer[key];
|
|
||||||
pointer[key] = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pointer[key] = pointer[key] ?? {};
|
|
||||||
pointer = pointer[key];
|
|
||||||
}
|
|
||||||
saveData(values);
|
|
||||||
_onDbChangeListeners.forEach((listener) =>
|
|
||||||
listener({ path: pathClone, new: value, old })
|
|
||||||
);
|
|
||||||
return value;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
addChangeListener: (callback) => {
|
|
||||||
_onDbChangeListeners.push(callback);
|
|
||||||
},
|
|
||||||
removeChangeListener: (callback) => {
|
|
||||||
_onDbChangeListeners = _onDbChangeListeners.filter((listener) => listener !== callback);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const ipcRenderer = {
|
|
||||||
sendMessage: (channel, data = undefined, namespace = 'notion-enhancer') => {
|
|
||||||
const { ipcRenderer } = require('electron');
|
|
||||||
channel = namespace ? `${namespace}:${channel}` : channel;
|
|
||||||
ipcRenderer.send(channel, data);
|
|
||||||
},
|
|
||||||
sendMessageToHost: (channel, data = undefined, namespace = 'notion-enhancer') => {
|
|
||||||
const { ipcRenderer } = require('electron');
|
|
||||||
channel = namespace ? `${namespace}:${channel}` : channel;
|
|
||||||
ipcRenderer.sendToHost(channel, data);
|
|
||||||
},
|
|
||||||
onMessage: (channel, callback, namespace = 'notion-enhancer') => {
|
|
||||||
const { ipcRenderer } = require('electron');
|
|
||||||
channel = namespace ? `${namespace}:${channel}` : channel;
|
|
||||||
ipcRenderer.on(channel, callback);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
globalThis.__enhancerElectronApi = {
|
|
||||||
platform: process.platform,
|
|
||||||
version: require('notion-enhancer/package.json').version,
|
|
||||||
db,
|
|
||||||
|
|
||||||
browser: isRenderer ? require('electron').remote.getCurrentWindow() : {},
|
|
||||||
webFrame: isRenderer ? require('electron').webFrame : {},
|
|
||||||
notionRequire: (path) => require(`../../${path}`),
|
|
||||||
notionPath: (path) => require('path').resolve(`${__dirname}/../../${path}`),
|
|
||||||
nodeRequire: (path) => require(path),
|
|
||||||
|
|
||||||
focusMenu: () => {
|
|
||||||
if (isRenderer) return ipcRenderer.sendMessage('focusMenu');
|
|
||||||
const { focusMenu } = require('notion-enhancer/worker.cjs');
|
|
||||||
return focusMenu();
|
|
||||||
},
|
|
||||||
focusNotion: () => {
|
|
||||||
if (isRenderer) return ipcRenderer.sendMessage('focusNotion');
|
|
||||||
const { focusNotion } = require('notion-enhancer/worker.cjs');
|
|
||||||
return focusNotion();
|
|
||||||
},
|
|
||||||
reload: () => {
|
|
||||||
if (isRenderer) return ipcRenderer.sendMessage('reload');
|
|
||||||
const { reload } = require('notion-enhancer/worker.cjs');
|
|
||||||
return reload();
|
|
||||||
},
|
|
||||||
|
|
||||||
getNotionWindows: () => {
|
|
||||||
const { getNotionWindows } = require('notion-enhancer/worker.cjs');
|
|
||||||
return getNotionWindows();
|
|
||||||
},
|
|
||||||
getFocusedNotionWindow: () => {
|
|
||||||
const { getFocusedNotionWindow } = require('notion-enhancer/worker.cjs');
|
|
||||||
return getFocusedNotionWindow();
|
|
||||||
},
|
|
||||||
|
|
||||||
ipcRenderer,
|
|
||||||
};
|
|
41
src/electron/env/env.mjs
vendored
41
src/electron/env/env.mjs
vendored
@ -1,41 +0,0 @@
|
|||||||
/**
|
|
||||||
* notion-enhancer: api
|
|
||||||
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
|
||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/** environment-specific methods and constants */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the environment/platform name code is currently being executed in
|
|
||||||
* @constant
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
export const name = globalThis.__enhancerElectronApi.platform;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the current version of the enhancer
|
|
||||||
* @constant
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
export const version = globalThis.__enhancerElectronApi.version;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* open the enhancer's menu
|
|
||||||
* @type {function}
|
|
||||||
*/
|
|
||||||
export const focusMenu = globalThis.__enhancerElectronApi.focusMenu;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* focus an active notion tab
|
|
||||||
* @type {function}
|
|
||||||
*/
|
|
||||||
export const focusNotion = globalThis.__enhancerElectronApi.focusNotion;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reload all notion and enhancer menu tabs to apply changes
|
|
||||||
* @type {function}
|
|
||||||
*/
|
|
||||||
export const reload = globalThis.__enhancerElectronApi.reload;
|
|
81
src/electron/env/fs.mjs
vendored
81
src/electron/env/fs.mjs
vendored
@ -1,81 +0,0 @@
|
|||||||
/**
|
|
||||||
* notion-enhancer: api
|
|
||||||
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
|
||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/** environment-specific file reading */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get an absolute path to files within notion
|
|
||||||
* @param {string} path - relative to the root notion/resources/app/ e.g. renderer/search.js
|
|
||||||
* @process electron
|
|
||||||
*/
|
|
||||||
export const notionPath = globalThis.__enhancerElectronApi.notionPath;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* transform a path relative to the enhancer root directory into an absolute path
|
|
||||||
* @param {string} path - a url or within-the-enhancer filepath
|
|
||||||
* @returns {string} an absolute filepath
|
|
||||||
*/
|
|
||||||
export const localPath = (path) => `notion://www.notion.so/__notion-enhancer/${path}`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fetch and parse a json file's contents
|
|
||||||
* @param {string} path - a url or within-the-enhancer filepath
|
|
||||||
* @param {object=} opts - the second argument of a fetch() request
|
|
||||||
* @returns {object} the json value of the requested file as a js object
|
|
||||||
*/
|
|
||||||
export const getJSON = (path, opts = {}) => {
|
|
||||||
path = path.replace(/^https:\/\/www\.notion\.so\//, 'notion://www.notion.so/');
|
|
||||||
const networkPath = path.startsWith('http') || path.startsWith('notion://');
|
|
||||||
if (networkPath) return fetch(path, opts).then((res) => res.json());
|
|
||||||
try {
|
|
||||||
return globalThis.__enhancerElectronApi.nodeRequire(`notion-enhancer/${path}`);
|
|
||||||
} catch {
|
|
||||||
return fetch(localPath(path), opts).then((res) => res.json());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fetch a text file's contents
|
|
||||||
* @param {string} path - a url or within-the-enhancer filepath
|
|
||||||
* @param {object=} opts - the second argument of a fetch() request
|
|
||||||
* @returns {string} the text content of the requested file
|
|
||||||
*/
|
|
||||||
export const getText = (path, opts = {}) => {
|
|
||||||
path = path.replace(/^https:\/\/www\.notion\.so\//, 'notion://www.notion.so/');
|
|
||||||
const networkPath = path.startsWith('http') || path.startsWith('notion://');
|
|
||||||
if (networkPath) return fetch(path, opts).then((res) => res.text());
|
|
||||||
try {
|
|
||||||
const fs = globalThis.__enhancerElectronApi.nodeRequire('fs');
|
|
||||||
return fs.readFileSync(notionPath(`notion-enhancer/${path}`));
|
|
||||||
} catch {
|
|
||||||
return fetch(localPath(path), opts).then((res) => res.text());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check if a file exists
|
|
||||||
* @param {string} path - a url or within-the-enhancer filepath
|
|
||||||
* @returns {boolean} whether or not the file exists
|
|
||||||
*/
|
|
||||||
export const isFile = async (path) => {
|
|
||||||
try {
|
|
||||||
const fs = globalThis.__enhancerElectronApi.nodeRequire('fs');
|
|
||||||
if (path.startsWith('http')) {
|
|
||||||
await fetch(path);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
fs.existsSync(notionPath(`notion-enhancer/${path}`));
|
|
||||||
} catch {
|
|
||||||
await fetch(localPath(path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
69
src/electron/env/storage.mjs
vendored
69
src/electron/env/storage.mjs
vendored
@ -1,69 +0,0 @@
|
|||||||
/**
|
|
||||||
* notion-enhancer: api
|
|
||||||
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
|
||||||
* (https://notion-enhancer.github.io/) under the MIT license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/** environment-specific data persistence */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get persisted data
|
|
||||||
* @param {string[]} path - the path of keys to the value being fetched
|
|
||||||
* @param {unknown=} fallback - a default value if the path is not matched
|
|
||||||
* @returns {Promise} value ?? fallback
|
|
||||||
*/
|
|
||||||
export const get = (path, fallback = undefined) => {
|
|
||||||
return globalThis.__enhancerElectronApi.db.get(path, fallback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* persist data
|
|
||||||
* @param {string[]} path - the path of keys to the value being set
|
|
||||||
* @param {unknown} value - the data to save
|
|
||||||
* @returns {Promise} resolves when data has been saved
|
|
||||||
*/
|
|
||||||
export const set = (path, value) => {
|
|
||||||
return globalThis.__enhancerElectronApi.db.set(path, value);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create a wrapper for accessing a partition of the storage
|
|
||||||
* @param {string[]} namespace - the path of keys to prefix all storage requests with
|
|
||||||
* @param {function=} get - the storage get function to be wrapped
|
|
||||||
* @param {function=} set - the storage set function to be wrapped
|
|
||||||
* @returns {object} an object with the wrapped get/set functions
|
|
||||||
*/
|
|
||||||
export const db = (namespace, getFunc = get, setFunc = set) => {
|
|
||||||
if (typeof namespace === 'string') namespace = [namespace];
|
|
||||||
return {
|
|
||||||
get: (path = [], fallback = undefined) => getFunc([...namespace, ...path], fallback),
|
|
||||||
set: (path, value) => setFunc([...namespace, ...path], value),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* add an event listener for changes in storage
|
|
||||||
* @param {onStorageChangeCallback} callback - called whenever a change in
|
|
||||||
* storage is initiated from the current process
|
|
||||||
*/
|
|
||||||
export const addChangeListener = (callback) => {
|
|
||||||
return globalThis.__enhancerElectronApi.db.addChangeListener(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* remove a listener added with storage.addChangeListener
|
|
||||||
* @param {onStorageChangeCallback} callback
|
|
||||||
*/
|
|
||||||
export const removeChangeListener = (callback) => {
|
|
||||||
return globalThis.__enhancerElectronApi.db.removeChangeListener(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @callback onStorageChangeCallback
|
|
||||||
* @param {object} event
|
|
||||||
* @param {string} event.path- the path of keys to the changed value
|
|
||||||
* @param {string=} event.new - the new value being persisted to the store
|
|
||||||
* @param {string=} event.old - the previous value associated with the key
|
|
||||||
*/
|
|
@ -1,28 +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';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
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?.frame || []) {
|
|
||||||
web.loadStylesheet(`repo/${mod._dir}/${sheet}`);
|
|
||||||
}
|
|
||||||
for (let script of mod.js?.frame || []) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
@ -1,46 +1,50 @@
|
|||||||
/**
|
/**
|
||||||
* 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";
|
||||||
|
|
||||||
module.exports = async function (target, __exports, __eval) {
|
module.exports = async (target, __exports, __eval) => {
|
||||||
require("notion-enhancer/electronApi.cjs");
|
// if (target === "renderer/preload") {
|
||||||
const api = require("notion-enhancer/api/index.cjs"),
|
const { initDatabase } = require("./node.cjs");
|
||||||
{ registry } = api;
|
|
||||||
|
|
||||||
if (target === "renderer/index") {
|
// require("notion-enhancer/electronApi.cjs");
|
||||||
document.addEventListener("readystatechange", (event) => {
|
// const api = require("notion-enhancer/api/index.cjs"),
|
||||||
if (document.readyState !== "complete") return false;
|
// { registry } = api;
|
||||||
const script = document.createElement("script");
|
|
||||||
script.type = "module";
|
|
||||||
script.src = api.fs.localPath("frame.mjs");
|
|
||||||
document.head.appendChild(script);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target === "renderer/preload") {
|
// if (target === "renderer/index") {
|
||||||
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 = api.fs.localPath("client.mjs");
|
// script.src = api.fs.localPath("frame.mjs");
|
||||||
document.head.appendChild(script);
|
// document.head.appendChild(script);
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (target === "main/main") {
|
// if (target === "renderer/preload") {
|
||||||
const { app } = require("electron");
|
const db = initDatabase("config");
|
||||||
app.whenReady().then(require("notion-enhancer/worker.cjs").listen);
|
// document.addEventListener("readystatechange", (event) => {
|
||||||
}
|
// if (document.readyState !== "complete") return false;
|
||||||
|
// const script = document.createElement("script");
|
||||||
|
// script.type = "module";
|
||||||
|
// script.src = api.fs.localPath("client.mjs");
|
||||||
|
// document.head.appendChild(script);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
|
// if (target === "main/main") {
|
||||||
for (const { source, target: scriptTarget } of (mod.js ? mod.js.electron : []) || []) {
|
// const { app } = require("electron");
|
||||||
if (`${target}.js` !== scriptTarget) continue;
|
// app.whenReady().then(require("notion-enhancer/worker.cjs").listen);
|
||||||
const script = require(`notion-enhancer/repo/${mod._dir}/${source}`);
|
// }
|
||||||
script(api, await registry.db(mod.id), __exports, __eval);
|
|
||||||
}
|
// for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
|
||||||
}
|
// for (const { source, target: scriptTarget } of (mod.js ? mod.js.electron : []) || []) {
|
||||||
|
// if (`${target}.js` !== scriptTarget) continue;
|
||||||
|
// const script = require(`notion-enhancer/repo/${mod._dir}/${source}`);
|
||||||
|
// script(api, await registry.db(mod.id), __exports, __eval);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
|
67
src/electron/node.cjs
Normal file
67
src/electron/node.cjs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* notion-enhancer
|
||||||
|
* (c) 2022 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
||||||
|
* (https://notion-enhancer.github.io/) under the MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const os = require("os"),
|
||||||
|
path = require("path"),
|
||||||
|
electron = require("electron"),
|
||||||
|
sqlite = require("better-sqlite3");
|
||||||
|
|
||||||
|
const notionRequire = (target) => require(`../../../${target}`),
|
||||||
|
notionPath = (target) => path.resolve(`${__dirname}/../../../${target}`),
|
||||||
|
notionPlatform = process.platform;
|
||||||
|
|
||||||
|
const enhancerRequire = (target) => require(`../${target}`),
|
||||||
|
enhancerPath = (target) => path.resolve(`${__dirname}/../${target}`),
|
||||||
|
enhancerUrl = (target) => `notion://www.notion.so/__notion-enhancer/${target}`,
|
||||||
|
enhancerVersion = enhancerRequire("package.json").version,
|
||||||
|
enhancerConfig = path.resolve(`${os.homedir()}/.notion-enhancer.db`);
|
||||||
|
|
||||||
|
const reloadApp = () => {
|
||||||
|
const args = process.argv.slice(1).filter((arg) => arg !== "--startup");
|
||||||
|
electron.app.relaunch({ args });
|
||||||
|
electron.app.exit();
|
||||||
|
};
|
||||||
|
|
||||||
|
let __db;
|
||||||
|
const initDatabase = (table) => {
|
||||||
|
const db = __db ?? sqlite(enhancerConfig),
|
||||||
|
init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} (
|
||||||
|
key TEXT PRIMARY KEY,
|
||||||
|
value TEXT,
|
||||||
|
mtime INTEGER
|
||||||
|
)`);
|
||||||
|
init.run();
|
||||||
|
__db = db;
|
||||||
|
|
||||||
|
const insert = db.prepare(`INSERT INTO ${table} (key, value, mtime) VALUES (?, ?, ?)`),
|
||||||
|
update = db.prepare(`UPDATE ${table} SET value = ?, mtime = ? WHERE key = ?`),
|
||||||
|
select = db.prepare(`SELECT * FROM ${table} WHERE key = ? LIMIT 1`),
|
||||||
|
dump = db.prepare(`SELECT * FROM ${table}`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
get: (key) => select.get(key)?.value,
|
||||||
|
set: (key, value) => {
|
||||||
|
if (select.get(key)) return update.run(value, key, Date.now());
|
||||||
|
else return insert.run(key, value, Date.now());
|
||||||
|
},
|
||||||
|
dump: () => dump.all(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
notionRequire,
|
||||||
|
notionPath,
|
||||||
|
notionPlatform,
|
||||||
|
enhancerRequire,
|
||||||
|
enhancerPath,
|
||||||
|
enhancerUrl,
|
||||||
|
enhancerVersion,
|
||||||
|
enhancerConfig,
|
||||||
|
reloadApp,
|
||||||
|
initDatabase,
|
||||||
|
};
|
29
src/mods/.github/workflows/update-parents.yml
vendored
29
src/mods/.github/workflows/update-parents.yml
vendored
@ -1,29 +0,0 @@
|
|||||||
name: 'update parent repositories'
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
sync:
|
|
||||||
name: update parent
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
repo: ['notion-enhancer/extension', 'notion-enhancer/desktop']
|
|
||||||
steps:
|
|
||||||
- name: checkout repo
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.CI_TOKEN }}
|
|
||||||
submodules: true
|
|
||||||
repository: ${{ matrix.repo }}
|
|
||||||
- name: pull updates
|
|
||||||
run: |
|
|
||||||
git pull --recurse-submodules
|
|
||||||
git submodule update --remote --recursive
|
|
||||||
- name: commit changes
|
|
||||||
uses: stefanzweifel/git-auto-commit-action@v4
|
|
||||||
with:
|
|
||||||
commit_message: '[${{ github.event.repository.name }}] ${{ github.event.head_commit.message }}'
|
|
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,5 +0,0 @@
|
|||||||
# notion-enhancer/repo
|
|
||||||
|
|
||||||
the collection of mods run by the notion-enhancer
|
|
||||||
|
|
||||||
[read the docs online](https://notion-enhancer.github.io/getting-started/features)
|
|
Loading…
Reference in New Issue
Block a user