Reject unsupported WebApp identity and align family guidance

Reject explicit NFC settings before WebApp services start and when settings
are loaded or saved. Preserve Legacy interoperability, and clarify host
support and the Commonlib-first publication prerequisite.
This commit is contained in:
vorotamoroz committed 2026-11-03 08:44:31 +00:00
1 parent 6f8df8f731
commit 9920da8f94
9 files changed
+272 -38

No files matched your search

+24 -5
View File
@@ -1,3 +1,4 @@
import { getPathNormalizationVersion } from "@vrtmrz/livesync-commonlib/settings";
import { useP2PSettingsPreparation } from "@/serviceFeatures/useP2PSettingsPreparation";
/** Browser runtime for Self-hosted LiveSync over the File System Access API. */
@@ -55,6 +56,14 @@ const DEFAULT_SETTINGS: Partial<ObsidianLiveSyncSettings> = {
autoSweepPluginsPeriodic: false,
};
function assertWebAppPathIdentity(settings: Partial<ObsidianLiveSyncSettings> | null): void {
if (getPathNormalizationVersion(settings ?? {}) === 1) {
throw new Error(
"WebApp supports Legacy path identity (pathNormalizationVersion: 0) only. Unicode NFC path identity is not supported."
);
}
}
export type WebAppRuntimeStatusKind = "info" | "warning" | "error" | "success";
export interface WebAppRuntimeOptions {
@@ -100,6 +109,7 @@ export class WebAppRuntime {
getSystemVaultName: () => this.rootHandle.name || "livesync-webapp",
settings: {
save: async (data) => {
assertWebAppPathIdentity(data);
try {
await this.saveSettingsToFile(data);
this.addLog("Saved to .livesync/settings.json", LOG_LEVEL_VERBOSE, "settings");
@@ -108,15 +118,17 @@ export class WebAppRuntime {
}
},
load: async () => {
let data: Partial<ObsidianLiveSyncSettings> | null = null;
try {
const data = await this.loadSettingsFromFile();
if (data) {
this.addLog("Loaded from .livesync/settings.json", LOG_LEVEL_VERBOSE, "settings");
return { ...DEFAULT_SETTINGS, ...data } as ObsidianLiveSyncSettings;
}
data = await this.loadSettingsFromFile();
} catch {
this.addLog("Failed to load settings; using defaults", LOG_LEVEL_NOTICE, "settings");
}
assertWebAppPathIdentity(data);
if (data) {
this.addLog("Loaded from .livesync/settings.json", LOG_LEVEL_VERBOSE, "settings");
return { ...DEFAULT_SETTINGS, ...data } as ObsidianLiveSyncSettings;
}
return DEFAULT_SETTINGS as ObsidianLiveSyncSettings;
},
},
@@ -205,6 +217,13 @@ export class WebAppRuntime {
throw new Error("The WebApp runtime has already been started");
}
try {
assertWebAppPathIdentity(await this.loadSettingsFromFile());
} catch (error) {
this.showError(`Failed to start: ${String(error)}`);
throw error;
}
// Create service context and hub
this.serviceHub = createLiveSyncBrowserServiceHub<ServiceContext>(this.createServiceOptions());
this.addLog("Self-hosted LiveSync WebApp", LOG_LEVEL_INFO, "initialise");