Compare commits

...

8 Commits

Author SHA1 Message Date
perf3ct
ac73d4c47a idk 2025-07-11 23:22:33 +00:00
perf3ct
e4006a83f2 idk 2025-07-11 23:16:18 +00:00
perf3ct
5782f93824 idk 2025-07-11 23:13:01 +00:00
perf3ct
c76e265b67 idk 2025-07-11 23:07:38 +00:00
perf3ct
fefcd9457f idk 2025-07-11 22:41:29 +00:00
perf3ct
72a779e695 idk 2025-07-11 22:35:05 +00:00
perf3ct
f6c27f458a idk 2025-07-11 21:43:32 +00:00
perf3ct
adfaa8b12c fix(docs): unpack the OpenAPI spec files, and have Swagger UI read from the unpacked files 2025-07-11 21:11:05 +00:00
2 changed files with 107 additions and 6 deletions

View File

@@ -37,7 +37,10 @@ const config: ForgeConfig = {
executableName: EXECUTABLE_NAME,
name: PRODUCT_NAME,
overwrite: true,
asar: true,
asar: {
unpack: "node_modules/swagger-ui-dist/**",
unpackDir: "assets"
},
icon: path.join(APP_ICON_PATH, "icon"),
...macosSignConfiguration,
windowsSign: windowsSignConfiguration,

View File

@@ -3,16 +3,102 @@ import swaggerUi from "swagger-ui-express";
import { join } from "path";
import yaml from "js-yaml";
import type { JsonObject } from "swagger-ui-express";
import { readFileSync } from "fs";
import { readFileSync, existsSync, readdirSync } from "fs";
import { RESOURCE_DIR } from "../services/resource_dir";
import log from "../services/log";
// Monkey patch fs.lstat to debug which files are causing the issue
const originalFs = require('fs');
const originalLstat = originalFs.lstat;
originalFs.lstat = function(path: string, callback: any) {
log.info(`[FS DEBUG] lstat called on: ${path}`);
return originalLstat.call(this, path, (err: any, stats: any) => {
if (err) {
log.error(`[FS DEBUG] lstat error on ${path}: ${err.message}`);
}
callback(err, stats);
});
};
export default function register(app: Application) {
const etapiDocument = yaml.load(readFileSync(join(RESOURCE_DIR, "etapi.openapi.yaml"), "utf8")) as JsonObject;
const apiDocument = JSON.parse(readFileSync(join(RESOURCE_DIR, "openapi.json"), "utf-8"));
log.info(`[DEBUG] Starting API docs registration`);
log.info(`[DEBUG] RESOURCE_DIR: ${RESOURCE_DIR}`);
// Clean trailing slashes from RESOURCE_DIR to prevent path resolution issues in packaged Electron apps
const cleanResourceDir = RESOURCE_DIR.replace(/[\\\/]+$/, '');
log.info(`[DEBUG] cleanResourceDir: ${cleanResourceDir}`);
// Check what's in the resource directory
try {
if (existsSync(cleanResourceDir)) {
const contents = readdirSync(cleanResourceDir);
log.info(`[DEBUG] Contents of ${cleanResourceDir}: ${contents.join(', ')}`);
} else {
log.info(`[DEBUG] Resource directory doesn't exist: ${cleanResourceDir}`);
}
} catch (e) {
log.error(`[DEBUG] Error reading resource directory: ${e}`);
}
// In packaged Electron apps, check if we need to read from the unpacked directory
let resourceDir = cleanResourceDir;
if (resourceDir.includes('app.asar')) {
log.info(`[DEBUG] Detected ASAR packaging`);
const unpackedDir = cleanResourceDir.replace('app.asar', 'app.asar.unpacked');
log.info(`[DEBUG] Checking unpacked dir: ${unpackedDir}`);
// Check what's in the unpacked directory
try {
if (existsSync(unpackedDir)) {
const unpackedContents = readdirSync(unpackedDir);
log.info(`[DEBUG] Contents of unpacked dir: ${unpackedContents.join(', ')}`);
if (existsSync(join(unpackedDir, "etapi.openapi.yaml"))) {
resourceDir = unpackedDir;
log.info(`[DEBUG] Using unpacked directory: ${resourceDir}`);
}
} else {
log.info(`[DEBUG] Unpacked directory doesn't exist: ${unpackedDir}`);
}
} catch (e) {
log.error(`[DEBUG] Error checking unpacked directory: ${e}`);
}
}
log.info(`[DEBUG] Final resourceDir: ${resourceDir}`);
log.info(`[DEBUG] About to load OpenAPI specs...`);
const etapiDocument = yaml.load(readFileSync(join(resourceDir, "etapi.openapi.yaml"), "utf8")) as JsonObject;
const apiDocument = JSON.parse(readFileSync(join(resourceDir, "openapi.json"), "utf-8"));
log.info(`[DEBUG] Successfully loaded OpenAPI documents`);
log.info(`[DEBUG] About to register swagger-ui endpoints...`);
// Check swagger-ui-dist location
try {
const swaggerPath = require.resolve('swagger-ui-dist/package.json');
log.info(`[DEBUG] swagger-ui-dist package.json found at: ${swaggerPath}`);
const swaggerDistPath = require.resolve('swagger-ui-dist');
log.info(`[DEBUG] swagger-ui-dist main module at: ${swaggerDistPath}`);
} catch (e) {
log.error(`[DEBUG] Error finding swagger-ui-dist: ${e}`);
}
app.use(
"/etapi/docs/",
swaggerUi.serveFiles(etapiDocument),
(req, res, next) => {
log.info(`[DEBUG] Request to /etapi/docs/: ${req.method} ${req.url}`);
// Temporarily disable ASAR for swagger-ui file access
const originalNoAsar = process.noAsar;
process.noAsar = true;
// Restore ASAR setting after response
res.on('finish', () => {
process.noAsar = originalNoAsar;
});
next();
},
swaggerUi.serve,
swaggerUi.setup(etapiDocument, {
explorer: true,
customSiteTitle: "TriliumNext ETAPI Documentation"
@@ -21,7 +107,19 @@ export default function register(app: Application) {
app.use(
"/api/docs/",
swaggerUi.serveFiles(apiDocument),
(req, res, next) => {
// Temporarily disable ASAR for swagger-ui file access
const originalNoAsar = process.noAsar;
process.noAsar = true;
// Restore ASAR setting after response
res.on('finish', () => {
process.noAsar = originalNoAsar;
});
next();
},
swaggerUi.serve,
swaggerUi.setup(apiDocument, {
explorer: true,
customSiteTitle: "TriliumNext Internal API Documentation"