From a2cace6c0f5fdc35c3d1a6a14dbaf6133e40c2b2 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 26 Mar 2026 21:52:58 +0200 Subject: [PATCH] feat(standalone): add support for environment variables --- .../src/lightweight/browser_routes.ts | 6 ++--- .../src/lightweight/platform_provider.ts | 22 +++++++++++++++++++ apps/client-standalone/src/local-bridge.ts | 1 + .../src/local-server-worker.ts | 12 ++++++++-- apps/desktop/src/platform_provider.ts | 4 ++++ apps/server/src/platform_provider.ts | 4 ++++ .../trilium-core/src/services/migration.ts | 4 ++-- .../trilium-core/src/services/options_init.ts | 5 +++-- .../trilium-core/src/services/platform.ts | 2 ++ 9 files changed, 50 insertions(+), 10 deletions(-) diff --git a/apps/client-standalone/src/lightweight/browser_routes.ts b/apps/client-standalone/src/lightweight/browser_routes.ts index c51aeaabaf..4901640a95 100644 --- a/apps/client-standalone/src/lightweight/browser_routes.ts +++ b/apps/client-standalone/src/lightweight/browser_routes.ts @@ -4,7 +4,7 @@ */ import { BootstrapDefinition } from '@triliumnext/commons'; -import { entity_changes, getContext, getSharedBootstrapItems, getSql, routes, sql_init } from '@triliumnext/core'; +import { entity_changes, getContext, getPlatform, getSharedBootstrapItems, getSql, routes, sql_init } from '@triliumnext/core'; import packageJson from '../../package.json' with { type: 'json' }; import { type BrowserRequest, BrowserRouter } from './browser_router'; @@ -255,9 +255,7 @@ function bootstrapRoute(): BootstrapDefinition { device: false as const, // Let the client detect device type. appPath: assetPath, instanceName: "standalone", - - // TODO: Fill properly - TRILIUM_SAFE_MODE: false + TRILIUM_SAFE_MODE: !!getPlatform().getEnv("TRILIUM_SAFE_MODE") }; if (!isDbInitialized) { diff --git a/apps/client-standalone/src/lightweight/platform_provider.ts b/apps/client-standalone/src/lightweight/platform_provider.ts index 9a1340eb4e..7c1d3c908c 100644 --- a/apps/client-standalone/src/lightweight/platform_provider.ts +++ b/apps/client-standalone/src/lightweight/platform_provider.ts @@ -1,6 +1,24 @@ import type { PlatformProvider } from "@triliumnext/core"; +/** Maps URL query parameter names to TRILIUM_ environment variable names. */ +const QUERY_TO_ENV: Record = { + "safeMode": "TRILIUM_SAFE_MODE", + "startNoteId": "TRILIUM_START_NOTE_ID", +}; + export default class StandalonePlatformProvider implements PlatformProvider { + + private envMap: Record = {}; + + constructor(queryString: string) { + const params = new URLSearchParams(queryString); + for (const [queryKey, envKey] of Object.entries(QUERY_TO_ENV)) { + if (params.has(queryKey)) { + this.envMap[envKey] = params.get(queryKey) || "true"; + } + } + } + crash(message: string): void { console.error("[Standalone] FATAL:", message); self.postMessage({ @@ -8,4 +26,8 @@ export default class StandalonePlatformProvider implements PlatformProvider { message }); } + + getEnv(key: string): string | undefined { + return this.envMap[key]; + } } diff --git a/apps/client-standalone/src/local-bridge.ts b/apps/client-standalone/src/local-bridge.ts index 216d6ee87b..dbd7e326d2 100644 --- a/apps/client-standalone/src/local-bridge.ts +++ b/apps/client-standalone/src/local-bridge.ts @@ -9,6 +9,7 @@ function showFatalErrorDialog(message: string) { export function startLocalServerWorker() { if (localWorker) return localWorker; localWorker = new LocalServerWorker(); + localWorker.postMessage({ type: "INIT", queryString: location.search }); // Handle worker errors during initialization localWorker.onerror = (event) => { diff --git a/apps/client-standalone/src/local-server-worker.ts b/apps/client-standalone/src/local-server-worker.ts index 86e945be10..be86cf8391 100644 --- a/apps/client-standalone/src/local-server-worker.ts +++ b/apps/client-standalone/src/local-server-worker.ts @@ -69,6 +69,7 @@ let coreModule: typeof import("@triliumnext/core") | null = null; let router: BrowserRouter | null = null; let initPromise: Promise | null = null; let initError: Error | null = null; +let queryString = ""; /** * Load all required modules using dynamic imports. @@ -153,7 +154,7 @@ async function initialize(): Promise { crypto: new BrowserCryptoProvider(), messaging: messagingProvider!, request: new FetchRequestProvider(), - platform: new StandalonePlatformProvider(), + platform: new StandalonePlatformProvider(queryString), translations: translationProvider, schema: schemaModule.default, dbConfig: { @@ -241,7 +242,14 @@ initialize().catch(err => { self.onmessage = async (event) => { const msg = event.data; - if (!msg || msg.type !== "LOCAL_REQUEST") return; + if (!msg) return; + + if (msg.type === "INIT") { + queryString = msg.queryString || ""; + return; + } + + if (msg.type !== "LOCAL_REQUEST") return; const { id, request } = msg; diff --git a/apps/desktop/src/platform_provider.ts b/apps/desktop/src/platform_provider.ts index e9dab7c5cf..01edf6087f 100644 --- a/apps/desktop/src/platform_provider.ts +++ b/apps/desktop/src/platform_provider.ts @@ -6,4 +6,8 @@ export default class DesktopPlatformProvider implements PlatformProvider { electron.dialog.showErrorBox(t("modals.error_title"), message); electron.app.exit(1); } + + getEnv(key: string): string | undefined { + return process.env[key]; + } } diff --git a/apps/server/src/platform_provider.ts b/apps/server/src/platform_provider.ts index ed9d5919e5..fe989370e9 100644 --- a/apps/server/src/platform_provider.ts +++ b/apps/server/src/platform_provider.ts @@ -5,4 +5,8 @@ export default class ServerPlatformProvider implements PlatformProvider { getLog().error(message); process.exit(1); } + + getEnv(key: string): string | undefined { + return process.env[key]; + } } diff --git a/packages/trilium-core/src/services/migration.ts b/packages/trilium-core/src/services/migration.ts index 34b9bc94a6..9ab5cf0cd6 100644 --- a/packages/trilium-core/src/services/migration.ts +++ b/packages/trilium-core/src/services/migration.ts @@ -24,7 +24,7 @@ async function migrate() { } // backup before attempting migration - if (!process.env.TRILIUM_INTEGRATION_TEST) { + if (!getPlatform().getEnv("TRILIUM_INTEGRATION_TEST")) { await backupService.backupNow( // creating a special backup for version 0.60.4, the changes in 0.61 are major. currentDbVersion === 214 ? `before-migration-v060` : "before-migration" @@ -123,7 +123,7 @@ function isDbUpToDate() { async function migrateIfNecessary() { const currentDbVersion = getDbVersion(); - if (currentDbVersion > appInfo.dbVersion && process.env.TRILIUM_IGNORE_DB_VERSION !== "true") { + if (currentDbVersion > appInfo.dbVersion && getPlatform().getEnv("TRILIUM_IGNORE_DB_VERSION") !== "true") { getPlatform().crash(t("migration.wrong_db_version", { version: currentDbVersion, targetVersion: appInfo.dbVersion })); } diff --git a/packages/trilium-core/src/services/options_init.ts b/packages/trilium-core/src/services/options_init.ts index a1fe29b46b..f1f76dd23b 100644 --- a/packages/trilium-core/src/services/options_init.ts +++ b/packages/trilium-core/src/services/options_init.ts @@ -1,6 +1,7 @@ import { type KeyboardShortcutWithRequiredActionName, type OptionMap, type OptionNames, SANITIZER_DEFAULT_ALLOWED_TAGS } from "@triliumnext/commons"; import appInfo from "./app_info.js"; +import { getPlatform } from "./platform.js"; import dateUtils from "./utils/date.js"; import keyboardActions from "./keyboard_actions.js"; import { getLog } from "./log.js"; @@ -237,12 +238,12 @@ export function initStartupOptions() { } } - if (process.env.TRILIUM_START_NOTE_ID || process.env.TRILIUM_SAFE_MODE) { + if (getPlatform().getEnv("TRILIUM_START_NOTE_ID") || getPlatform().getEnv("TRILIUM_SAFE_MODE")) { optionService.setOption( "openNoteContexts", JSON.stringify([ { - notePath: process.env.TRILIUM_START_NOTE_ID || "root", + notePath: getPlatform().getEnv("TRILIUM_START_NOTE_ID") || "root", active: true } ]) diff --git a/packages/trilium-core/src/services/platform.ts b/packages/trilium-core/src/services/platform.ts index 8c5d9e0929..91efa22f06 100644 --- a/packages/trilium-core/src/services/platform.ts +++ b/packages/trilium-core/src/services/platform.ts @@ -3,6 +3,8 @@ */ export interface PlatformProvider { crash(message: string): void; + /** Returns the value of an environment variable, or undefined if not set. */ + getEnv(key: string): string | undefined; } let platformProvider: PlatformProvider | null = null;