load bundled plugins via virtual-plugin loader

This commit is contained in:
Nystik
2026-05-24 17:41:13 +02:00
parent f05ee9e856
commit 9eeff3c1b3
11 changed files with 152 additions and 96 deletions

View File

@@ -58,7 +58,7 @@ COPY packages/bridge/styles.css ./packages/bridge/
COPY --from=build /app/packages/shim/dist/shim-loader.js ./packages/shim/dist/shim-loader.js
COPY --from=build /app/packages/ui/dist/ignis-ui.js ./packages/ui/dist/ignis-ui.js
COPY --from=build /app/packages/bridge/main.js ./packages/bridge/main.js
COPY --from=build /app/apps/ignis-server/server/plugins/headless-sync/obsidian/main.js ./apps/ignis-server/server/plugins/headless-sync/obsidian/main.js
COPY --from=build /app/apps/ignis-server/server/plugins/headless-sync/obsidian/dist/ ./apps/ignis-server/server/plugins/headless-sync/obsidian/dist/
RUN chmod +x /app/apps/ignis-server/scripts/entrypoint.sh

View File

@@ -13,7 +13,11 @@ const {
BRIDGE_PLUGIN_ID,
migratePluginsFromAllVaults,
} = require("./bridge-plugin");
const { initPlugins, shutdownPlugins } = require("./plugin-system/manager");
const {
initPlugins,
shutdownPlugins,
getBundledPluginDirs,
} = require("./plugin-system/manager");
const pluginRoutes = require("./routes/plugins");
writeCoalescer.configure({ writeCoalesceMs: config.writeCoalesceMs });
const { flushAll } = writeCoalescer;
@@ -173,8 +177,19 @@ const server = app.listen(config.port, async () => {
console.log(`[ignis] Vault root: ${config.vaultRoot}`);
console.log(`[ignis] Vaults: ${Object.keys(config.vaults).join(", ")}`);
await migratePluginsFromAllVaults(config.vaultRoot, [BRIDGE_PLUGIN_ID]);
await initPlugins({ app, config, wss, watcher });
const bundledPluginDirs = getBundledPluginDirs();
for (const { distDir } of bundledPluginDirs) {
app.use(express.static(distDir));
}
await migratePluginsFromAllVaults(config.vaultRoot, [
BRIDGE_PLUGIN_ID,
...bundledPluginDirs.map((d) => d.bundledPluginId),
]);
bootstrapRoutes
.warmUp()
.catch((e) => console.warn("[bootstrap] warm-up error:", e.message));

View File

@@ -40,17 +40,16 @@ function discoverPlugins(pluginsDir) {
continue;
}
let bundledPluginId = null;
let bundledManifest = null;
if (plugin.obsidianPlugin) {
try {
const manifest = JSON.parse(
bundledManifest = JSON.parse(
fs.readFileSync(
path.join(plugin.obsidianPlugin, "manifest.json"),
"utf-8",
),
);
bundledPluginId = manifest.id;
} catch {
// No valid bundled plugin manifest
}
@@ -61,7 +60,8 @@ function discoverPlugins(pluginsDir) {
name: plugin.name,
description: plugin.description || "",
obsidianPlugin: plugin.obsidianPlugin || null,
bundledPluginId,
bundledPluginId: bundledManifest ? bundledManifest.id : null,
bundledManifest,
module: plugin,
});

View File

@@ -3,10 +3,6 @@ const path = require("path");
const express = require("express");
const { discoverPlugins } = require("./discovery");
const configStore = require("./config-store");
const {
installObsidianPlugin,
removeObsidianPlugin,
} = require("./obsidian-plugin");
let discoveredPlugins = new Map();
const loadedPlugins = new Map();
@@ -50,18 +46,6 @@ async function initPlugins(ctx) {
continue;
}
const discovered = discoveredPlugins.get(pluginId);
if (discovered.obsidianPlugin) {
try {
await installObsidianPlugin(discovered.obsidianPlugin, vaultPath);
} catch (e) {
console.error(
`[plugins] Failed to verify bundled plugin for ${pluginId} in ${vaultId}: ${e.message}`,
);
}
}
const loaded = loadedPlugins.get(pluginId);
if (loaded?.module?.onVaultEnabled) {
@@ -182,25 +166,6 @@ async function enablePluginForVault(pluginId, vaultId) {
await loadPlugin(pluginId);
}
if (discovered.obsidianPlugin) {
try {
const result = await installObsidianPlugin(
discovered.obsidianPlugin,
vaultPath,
);
if (result.installed) {
console.log(
`[plugins] Installed bundled Obsidian plugin for ${pluginId} in vault: ${vaultId}`,
);
}
} catch (e) {
console.error(
`[plugins] Failed to install bundled plugin for ${pluginId}: ${e.message}`,
);
}
}
const loaded = loadedPlugins.get(pluginId);
if (loaded?.module?.onVaultEnabled) {
@@ -227,25 +192,6 @@ async function disablePluginForVault(pluginId, vaultId) {
await loaded.module.onVaultDisabled(vaultId, vaultPath);
}
if (discovered.obsidianPlugin) {
try {
const result = await removeObsidianPlugin(
discovered.obsidianPlugin,
vaultPath,
);
if (result.removed) {
console.log(
`[plugins] Removed bundled Obsidian plugin for ${pluginId} from vault: ${vaultId}`,
);
}
} catch (e) {
console.error(
`[plugins] Failed to remove bundled plugin for ${pluginId}: ${e.message}`,
);
}
}
const enabledVaults = configStore.getEnabledVaults(pluginConfig, pluginId);
const updated = enabledVaults.filter((id) => id !== vaultId);
configStore.setEnabledVaults(pluginConfig, pluginId, updated);
@@ -256,6 +202,47 @@ async function disablePluginForVault(pluginId, vaultId) {
}
}
function getBundledPluginDirs() {
const dirs = [];
for (const [, discovered] of discoveredPlugins) {
if (discovered.obsidianPlugin && discovered.bundledPluginId) {
dirs.push({
bundledPluginId: discovered.bundledPluginId,
distDir: path.join(discovered.obsidianPlugin, "dist"),
});
}
}
return dirs;
}
function getVirtualPluginsForVault(vaultId, version) {
const v = version ? `?v=${version}` : "";
const result = [];
for (const [pluginId, discovered] of discoveredPlugins) {
if (!discovered.obsidianPlugin || !discovered.bundledPluginId) {
continue;
}
const enabledVaults = configStore.getEnabledVaults(pluginConfig, pluginId);
if (!enabledVaults.includes(vaultId)) {
continue;
}
result.push({
id: discovered.bundledPluginId,
scriptUrl: `/${discovered.bundledPluginId}.js${v}`,
cssUrl: `/${discovered.bundledPluginId}.css${v}`,
manifest: discovered.bundledManifest,
});
}
return result;
}
function getDiscoveredPlugins() {
const result = [];
@@ -280,4 +267,6 @@ module.exports = {
enablePluginForVault,
disablePluginForVault,
getDiscoveredPlugins,
getBundledPluginDirs,
getVirtualPluginsForVault,
};

View File

@@ -9,7 +9,11 @@ const fsp = fs.promises;
const path = require("path");
const zlib = require("zlib");
const config = require("../config");
const { getDiscoveredPlugins } = require("../plugin-system/manager");
const {
getDiscoveredPlugins,
getVirtualPluginsForVault,
} = require("../plugin-system/manager");
const { getVersion } = require("../version");
const router = express.Router();
@@ -135,6 +139,7 @@ async function buildEntry(vaultId) {
tree,
// In demo mode, hide server-side plugins from the client.
plugins: config.demoMode ? [] : getDiscoveredPlugins(),
virtualPlugins: getVirtualPluginsForVault(vaultId, getVersion()),
};
const jsonBuf = Buffer.from(JSON.stringify(response));