mirror of
https://github.com/Nystik-gh/ignis.git
synced 2026-06-17 04:35:53 +00:00
Merge branch 'main' into filewatcher
This commit is contained in:
@@ -3,12 +3,8 @@ const fs = require("fs");
|
||||
|
||||
// VAULT_ROOT: a directory that contains vault folders.
|
||||
// Each subdirectory is a vault. New vaults are created as new subdirs.
|
||||
// Falls back to parent of VAULT_PATH (single-vault compatibility) or ./vaults.
|
||||
const vaultRoot =
|
||||
process.env.VAULT_ROOT ||
|
||||
(process.env.VAULT_PATH
|
||||
? path.dirname(process.env.VAULT_PATH)
|
||||
: path.join(__dirname, "..", "vaults"));
|
||||
process.env.VAULT_ROOT || path.join(__dirname, "..", "vaults");
|
||||
|
||||
// Ensure vault root exists
|
||||
try {
|
||||
@@ -32,8 +28,11 @@ function discoverVaults() {
|
||||
console.error("[config] Failed to read VAULT_ROOT:", vaultRoot, e.message);
|
||||
}
|
||||
|
||||
// Create a default vault if none exist
|
||||
if (Object.keys(vaults).length === 0) {
|
||||
// Optionally create a default vault if none exist
|
||||
if (
|
||||
Object.keys(vaults).length === 0 &&
|
||||
process.env.AUTO_CREATE_DEFAULT === "true"
|
||||
) {
|
||||
const defaultPath = path.join(vaultRoot, "My Vault");
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const express = require("express");
|
||||
const path = require("path");
|
||||
const compression = require("compression");
|
||||
const config = require("./config");
|
||||
const { setupWebSocket } = require("./ws");
|
||||
const { installPluginInAllVaults } = require("./install-plugin");
|
||||
@@ -12,6 +13,7 @@ const ANSI_RESET = "\x1b[0m";
|
||||
const app = express();
|
||||
|
||||
app.use(express.json({ limit: "50mb" }));
|
||||
app.use(compression());
|
||||
|
||||
// logger middleware
|
||||
app.use((req, res, next) => {
|
||||
@@ -43,10 +45,12 @@ app.use((req, res, next) => {
|
||||
const fsRoutes = require("./routes/fs");
|
||||
const vaultRoutes = require("./routes/vault");
|
||||
const proxyRoutes = require("./routes/proxy");
|
||||
const versionRoutes = require("./routes/version");
|
||||
|
||||
app.use("/api/fs", fsRoutes);
|
||||
app.use("/api/vault", vaultRoutes);
|
||||
app.use("/api/proxy", proxyRoutes);
|
||||
app.use("/api/version", versionRoutes);
|
||||
|
||||
// Serve vault files for resource URLs (images, attachments, etc.)
|
||||
// Vault ID is the first path segment: /vault-files/<vault-id>/path/to/file
|
||||
@@ -70,6 +74,20 @@ app.use("/vault-files", (req, res, next) => {
|
||||
express.static(vaultPath)(req, res, next);
|
||||
});
|
||||
|
||||
// Serve dist files with cache headers based on version param
|
||||
app.use((req, res, next) => {
|
||||
if (req.path.match(/\/(ignis-ui|shim-loader)\.js$/)) {
|
||||
if (req.query.v) {
|
||||
// Versioned assets - cache for 1 year
|
||||
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
||||
} else {
|
||||
// No version param - short cache for dev/fallback
|
||||
res.setHeader("Cache-Control", "public, max-age=300");
|
||||
}
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(express.static(path.join(__dirname, "..", "dist")));
|
||||
|
||||
app.use(express.static(config.obsidianAssetsPath));
|
||||
|
||||
@@ -1,6 +1,46 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
// .ignis metadata helpers
|
||||
async function getIgnisMeta(vaultPath) {
|
||||
const ignisDir = path.join(vaultPath, ".ignis");
|
||||
const metaFile = path.join(ignisDir, "meta.json");
|
||||
|
||||
try {
|
||||
const content = await fs.promises.readFile(metaFile, "utf-8");
|
||||
return JSON.parse(content);
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
async function setIgnisMeta(vaultPath, data) {
|
||||
const ignisDir = path.join(vaultPath, ".ignis");
|
||||
const metaFile = path.join(ignisDir, "meta.json");
|
||||
|
||||
await fs.promises.mkdir(ignisDir, { recursive: true });
|
||||
await fs.promises.writeFile(metaFile, JSON.stringify(data, null, 2));
|
||||
}
|
||||
|
||||
async function checkPluginInstalled(vaultPath) {
|
||||
const pluginDir = path.join(
|
||||
vaultPath,
|
||||
".obsidian",
|
||||
"plugins",
|
||||
"ignis-bridge",
|
||||
);
|
||||
const manifestPath = path.join(pluginDir, "manifest.json");
|
||||
const mainPath = path.join(pluginDir, "main.js");
|
||||
|
||||
try {
|
||||
await fs.promises.access(manifestPath);
|
||||
await fs.promises.access(mainPath);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function installPluginInVault(vaultPath) {
|
||||
const obsidianDir = path.join(vaultPath, ".obsidian");
|
||||
const pluginDir = path.join(obsidianDir, "plugins", "ignis-bridge");
|
||||
@@ -62,4 +102,10 @@ async function installPluginInAllVaults(vaultRoot) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { installPluginInVault, installPluginInAllVaults };
|
||||
module.exports = {
|
||||
installPluginInVault,
|
||||
installPluginInAllVaults,
|
||||
getIgnisMeta,
|
||||
setIgnisMeta,
|
||||
checkPluginInstalled,
|
||||
};
|
||||
|
||||
@@ -28,10 +28,19 @@ router.post("/", async (req, res) => {
|
||||
const upstream = await fetch(url, fetchOpts);
|
||||
const respBody = Buffer.from(await upstream.arrayBuffer());
|
||||
|
||||
// Forward response headers
|
||||
// Forward response headers, stripping hop-by-hop / encoding headers
|
||||
// since the body is already decompressed by Node's fetch
|
||||
const skipHeaders = new Set([
|
||||
"content-encoding",
|
||||
"transfer-encoding",
|
||||
"content-length",
|
||||
"connection",
|
||||
]);
|
||||
const respHeaders = {};
|
||||
upstream.headers.forEach((val, key) => {
|
||||
respHeaders[key] = val;
|
||||
if (!skipHeaders.has(key)) {
|
||||
respHeaders[key] = val;
|
||||
}
|
||||
});
|
||||
|
||||
res.json({
|
||||
|
||||
@@ -2,6 +2,12 @@ const express = require("express");
|
||||
const fs = require("fs");
|
||||
const config = require("../config");
|
||||
const path = require("path");
|
||||
const {
|
||||
checkPluginInstalled,
|
||||
getIgnisMeta,
|
||||
setIgnisMeta,
|
||||
installPluginInVault,
|
||||
} = require("../install-plugin");
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -19,7 +25,7 @@ router.get("/list", (req, res) => {
|
||||
});
|
||||
|
||||
// GET /api/vault/info?vault=<id> - returns info for a specific vault
|
||||
router.get("/info", (req, res) => {
|
||||
router.get("/info", async (req, res) => {
|
||||
const vaultId = req.query.vault || config.defaultVaultId;
|
||||
const vaultPath = config.getVaultPath(vaultId);
|
||||
|
||||
@@ -27,12 +33,19 @@ router.get("/info", (req, res) => {
|
||||
return res.status(404).json({ error: "Vault not found", id: vaultId });
|
||||
}
|
||||
|
||||
const pluginInstalled = await checkPluginInstalled(vaultPath);
|
||||
const ignisMeta = await getIgnisMeta(vaultPath);
|
||||
|
||||
res.json({
|
||||
id: vaultId,
|
||||
name: vaultId,
|
||||
path: vaultPath,
|
||||
platform: process.platform,
|
||||
version: config.obsidianVersion,
|
||||
ignisPlugin: {
|
||||
installed: pluginInstalled,
|
||||
prompted: ignisMeta.pluginPrompted || false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -143,4 +156,42 @@ router.delete("/remove", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/vault/install-plugin { vault, dismiss } - install plugin or mark as prompted
|
||||
router.post("/install-plugin", async (req, res) => {
|
||||
const vaultId = req.body?.vault;
|
||||
const dismiss = req.body?.dismiss || false;
|
||||
|
||||
if (!vaultId) {
|
||||
return res.status(400).json({ error: "Missing vault ID" });
|
||||
}
|
||||
|
||||
const vaultPath = config.getVaultPath(vaultId);
|
||||
|
||||
if (!vaultPath) {
|
||||
return res.status(404).json({ error: "Vault not found" });
|
||||
}
|
||||
|
||||
try {
|
||||
const meta = await getIgnisMeta(vaultPath);
|
||||
|
||||
if (dismiss) {
|
||||
// User clicked "Don't Ask Again" or "Not Now"
|
||||
meta.pluginPrompted = true;
|
||||
await setIgnisMeta(vaultPath, meta);
|
||||
|
||||
return res.json({ ok: true, prompted: true });
|
||||
} else {
|
||||
// User wants to install the plugin
|
||||
const installed = await installPluginInVault(vaultPath);
|
||||
|
||||
meta.pluginPrompted = true;
|
||||
await setIgnisMeta(vaultPath, meta);
|
||||
|
||||
return res.json({ ok: true, installed, prompted: true });
|
||||
}
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: e.message, code: e.code });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
17
server/routes/version.js
Normal file
17
server/routes/version.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const express = require("express");
|
||||
const { getVersion } = require("../version");
|
||||
const config = require("../config");
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get("/", (req, res) => {
|
||||
const pkg = require("../../package.json");
|
||||
|
||||
res.json({
|
||||
version: getVersion(),
|
||||
semver: pkg.version,
|
||||
obsidianVersion: config.obsidianVersion,
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
23
server/version.js
Normal file
23
server/version.js
Normal file
@@ -0,0 +1,23 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { execSync } = require("child_process");
|
||||
|
||||
function getVersion() {
|
||||
const pkg = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf-8"),
|
||||
);
|
||||
const semver = pkg.version;
|
||||
|
||||
let hash;
|
||||
try {
|
||||
hash = execSync("git rev-parse --short=7 HEAD", {
|
||||
encoding: "utf-8",
|
||||
}).trim();
|
||||
} catch (e) {
|
||||
hash = Date.now().toString(36).slice(-7);
|
||||
}
|
||||
|
||||
return `${semver}-${hash}`;
|
||||
}
|
||||
|
||||
module.exports = { getVersion };
|
||||
Reference in New Issue
Block a user