refactor: organise source files by ownership

Separate host-independent helpers under common/core and colocate feature
support code with its owners. Update imports, tests, and source-layout
guidance while preserving runtime behaviour.
This commit is contained in:
vorotamoroz committed 2026-11-13 10:58:24 +00:00
1 parent 9a0941647b
commit 73adfe3a74
115 files changed
+115 -103

No files matched your search

@@ -0,0 +1,32 @@
type LegacyLocalDatabaseSelection = {
useIndexedDBAdapter: boolean;
};
type LegacyBulkChunkPreSendSettings = {
sendChunksBulk: boolean;
sendChunksBulkMaxSize: number;
};
/**
* Returns whether persisted settings select the legacy PouchDB IndexedDB adapter.
*
* New local databases use IDB. Existing devices must retain this operative value until their local database has
* been explicitly migrated, so compatibility code must not treat the setting as inert.
*/
export function usesLegacyIndexedDBAdapter(settings: LegacyLocalDatabaseSelection): boolean {
return settings.useIndexedDBAdapter;
}
/**
* Disables the removed automatic bulk chunk pre-send option in persisted settings.
*
* The field remains readable only so older settings and Setup URIs can be migrated to the supported behaviour.
*
* @returns `true` when the legacy setting was enabled and has been changed.
*/
export function disableLegacyBulkChunkPreSend(settings: LegacyBulkChunkPreSendSettings): boolean {
if (!settings.sendChunksBulk) return false;
settings.sendChunksBulk = false;
settings.sendChunksBulkMaxSize = 1;
return true;
}
@@ -0,0 +1,22 @@
import { describe, expect, it } from "vitest";
import { disableLegacyBulkChunkPreSend, usesLegacyIndexedDBAdapter } from "./compatibilitySettings.ts";
describe("compatibility settings", () => {
it.each([true, false])("preserves the operative legacy adapter selection (%s)", (useIndexedDBAdapter) => {
expect(usesLegacyIndexedDBAdapter({ useIndexedDBAdapter })).toBe(useIndexedDBAdapter);
});
it("disables automatic bulk chunk pre-send and restores its inert size value", () => {
const settings = { sendChunksBulk: true, sendChunksBulkMaxSize: 16 };
expect(disableLegacyBulkChunkPreSend(settings)).toBe(true);
expect(settings).toEqual({ sendChunksBulk: false, sendChunksBulkMaxSize: 1 });
});
it("leaves an already migrated bulk chunk setting unchanged", () => {
const settings = { sendChunksBulk: false, sendChunksBulkMaxSize: 4 };
expect(disableLegacyBulkChunkPreSend(settings)).toBe(false);
expect(settings).toEqual({ sendChunksBulk: false, sendChunksBulkMaxSize: 4 });
});
});
@@ -0,0 +1,10 @@
import { createNewVaultSettings as createCommonlibNewVaultSettings } from "@vrtmrz/livesync-commonlib/settings";
import type { ObsidianLiveSyncSettings } from "@vrtmrz/livesync-commonlib/compat/common/types";
/** Create settings for a new LiveSync environment. */
export function createNewVaultSettings(): ObsidianLiveSyncSettings {
return {
...createCommonlibNewVaultSettings(),
pathNormalizationVersion: 1,
};
}
@@ -0,0 +1,39 @@
import { describe, expect, it } from "vitest";
import {
NEW_VAULT_SETTINGS,
SETTINGS_SCHEMA_DEFAULTS,
createNewVaultSettings as createCommonlibNewVaultSettings,
} from "@vrtmrz/livesync-commonlib/settings";
import { createNewVaultSettings } from "./newVaultSettings.ts";
describe("createNewVaultSettings", () => {
it("selects NFC path identity only for new host settings", () => {
expect(SETTINGS_SCHEMA_DEFAULTS.pathNormalizationVersion).toBe(0);
expect(NEW_VAULT_SETTINGS.pathNormalizationVersion).toBe(0);
expect(createCommonlibNewVaultSettings().pathNormalizationVersion).toBe(0);
expect(createNewVaultSettings().pathNormalizationVersion).toBe(1);
});
it("keeps remote configurations independent of shared and other new-Vault settings", () => {
const first = createNewVaultSettings();
const second = createNewVaultSettings();
const shared = createCommonlibNewVaultSettings();
expect(first.remoteConfigurations).not.toBe(second.remoteConfigurations);
expect(first.remoteConfigurations).not.toBe(shared.remoteConfigurations);
expect(first.pluginSyncExtendedSetting).not.toBe(second.pluginSyncExtendedSetting);
expect(first.pluginSyncExtendedSetting).not.toBe(shared.pluginSyncExtendedSetting);
first.remoteConfigurations.example = {
id: "example",
name: "Example",
uri: "sls+http://localhost/",
isEncrypted: false,
};
expect(second.remoteConfigurations).toEqual({});
expect(shared.remoteConfigurations).toEqual({});
expect(NEW_VAULT_SETTINGS.remoteConfigurations).toEqual({});
expect(NEW_VAULT_SETTINGS.pluginSyncExtendedSetting).toEqual({});
});
});
@@ -0,0 +1,20 @@
import { ConnectionStringParser } from "@vrtmrz/livesync-commonlib/compat/common/ConnectionString";
import {
REMOTE_P2P,
type ObsidianLiveSyncSettings,
} from "@vrtmrz/livesync-commonlib/compat/common/types";
/** Returns whether the selected main remote represents the P2P-only setup. */
export function isP2PMainRemote(settings: ObsidianLiveSyncSettings): boolean {
if (settings.remoteType === REMOTE_P2P) return true;
const activeId = settings.activeConfigurationId?.trim();
const activeConfiguration = activeId ? settings.remoteConfigurations?.[activeId] : undefined;
if (!activeConfiguration) return false;
try {
return ConnectionStringParser.parse(activeConfiguration.uri).type === "p2p";
} catch {
return false;
}
}
+63
View File
@@ -0,0 +1,63 @@
import {
hasManagedP2PTurnConfiguration,
type ObsidianLiveSyncSettings,
} from "@vrtmrz/livesync-commonlib/compat/common/types";
import { pickP2PSyncSettings } from "@vrtmrz/livesync-commonlib/compat/common/utils";
import { CLOUDFLARE_TURN_TYPE } from "@/integrations/cloudflare/settings";
/** Include inactive profiles when deciding whether Markdown would disclose provider settings. */
export function hasManagedTurnSettings(settings: Partial<ObsidianLiveSyncSettings>): boolean {
return (
hasManagedP2PTurnConfiguration(settings) ||
Object.values(settings.remoteConfigurations ?? {}).some(({ uri }) => {
if (!uri.startsWith("sls+p2p://")) return false;
const queryStart = uri.indexOf("?");
return (
queryStart >= 0 && new URLSearchParams(uri.slice(queryStart + 1).split("#", 1)[0]).has("managedType")
);
})
);
}
/** Reports retain a recognised provider label and omit issued credentials. */
export function redactTurnSettingsForReport(settings: Partial<ObsidianLiveSyncSettings>): void {
if (settings.P2P_managedType) {
settings.P2P_managedType =
settings.P2P_managedType === CLOUDFLARE_TURN_TYPE ? CLOUDFLARE_TURN_TYPE : "redacted";
}
if (settings.P2P_managedId !== undefined) settings.P2P_managedId = "redacted";
if (settings.P2P_managedToken !== undefined) settings.P2P_managedToken = "redacted";
delete settings.P2P_iceServers;
delete settings.P2P_iceServersExpiresAt;
}
/** Managed connection profiles are shared through Setup URIs and QR codes. */
export function omitManagedTurnProfilesFromMarkdown(settings: Partial<ObsidianLiveSyncSettings>): void {
delete settings.P2P_iceServers;
delete settings.P2P_iceServersExpiresAt;
if (!hasManagedTurnSettings(settings)) return;
delete settings.P2P_managedType;
delete settings.P2P_managedId;
delete settings.P2P_managedToken;
delete settings.remoteConfigurations;
delete settings.activeConfigurationId;
delete settings.P2P_ActiveRemoteConfigurationId;
}
/** Preserve the complete connection when Markdown omits its profile group. */
export function preserveManagedTurnProfilesOnMarkdownImport(
incoming: Partial<ObsidianLiveSyncSettings>,
current: ObsidianLiveSyncSettings,
merged: ObsidianLiveSyncSettings
): void {
if (
!hasManagedTurnSettings(current) ||
incoming.remoteConfigurations !== undefined ||
incoming.P2P_managedType !== undefined
)
return;
merged.remoteConfigurations = structuredClone(current.remoteConfigurations);
merged.activeConfigurationId = current.activeConfigurationId;
merged.P2P_ActiveRemoteConfigurationId = current.P2P_ActiveRemoteConfigurationId;
Object.assign(merged, pickP2PSyncSettings(current));
}
@@ -0,0 +1,131 @@
import { MemoryValueStore } from "@vrtmrz/value-store";
import { describe, expect, it } from "vitest";
import {
DEFAULT_SETTINGS,
REMOTE_P2P,
type ObsidianLiveSyncSettings,
} from "@vrtmrz/livesync-commonlib/compat/common/types";
import {
SettingService,
type SettingServiceDependencies,
} from "@vrtmrz/livesync-commonlib/compat/services/base/SettingService";
import { ServiceContext } from "@vrtmrz/livesync-commonlib/compat/services/base/ServiceBase";
import { ConnectionStringParser } from "@vrtmrz/livesync-commonlib/compat/common/ConnectionString";
import {
hasManagedTurnSettings,
omitManagedTurnProfilesFromMarkdown,
preserveManagedTurnProfilesOnMarkdownImport,
redactTurnSettingsForReport,
} from "./turnPrivacy";
class MemorySettingService extends SettingService {
saved?: ObsidianLiveSyncSettings;
protected saveData(settings: ObsidianLiveSyncSettings) {
this.saved = structuredClone(settings);
return Promise.resolve();
}
protected loadData() {
return Promise.resolve(this.saved);
}
}
function configuredSettings() {
return {
...DEFAULT_SETTINGS,
P2P_managedType: "CF",
P2P_managedId: "private-key-id",
P2P_managedToken: "private-token",
remoteConfigurations: {
managed: {
id: "managed",
name: "Managed TURN",
isEncrypted: false,
uri: "sls+p2p://room?managedType=CF&managedId=private-key-id&token=private-token",
},
},
activeConfigurationId: "central",
P2P_ActiveRemoteConfigurationId: "managed",
};
}
describe("managed TURN settings privacy", () => {
it("preserves the active managed room through Markdown import, save, and reload", async () => {
const current = {
...configuredSettings(),
remoteType: REMOTE_P2P,
activeConfigurationId: "managed",
P2P_roomID: "local-room",
P2P_relays: "wss://local-relay.example.test",
P2P_passphrase: "local-passphrase",
};
const originalURI = ConnectionStringParser.serialize({ type: "p2p", settings: current });
current.remoteConfigurations.managed.uri = originalURI;
const service = new MemorySettingService(new ServiceContext(), {
deviceValues: new MemoryValueStore(),
APIService: {
getSystemVaultName: () => "test-vault",
getAppID: () => "test-app",
addLog: () => undefined,
confirm: { askString: async () => "" },
} as unknown as SettingServiceDependencies["APIService"],
});
service.settings = structuredClone(current);
const incoming: Partial<ObsidianLiveSyncSettings> = {
P2P_roomID: "imported-room",
P2P_relays: "wss://imported-relay.example.test",
P2P_passphrase: "imported-passphrase",
};
const merged = { ...structuredClone(DEFAULT_SETTINGS), ...incoming };
preserveManagedTurnProfilesOnMarkdownImport(incoming, current, merged);
await service.applyExternalSettings(merged, true);
const saved = service.saved!.remoteConfigurations.managed;
const uri = saved.isEncrypted ? await service.decryptConfigurationItem(saved.uri, "*") : saved.uri;
expect(uri).toBe(originalURI);
expect(service.settings.P2P_roomID).toBe("local-room");
await service.loadSettings();
expect(service.settings.P2P_roomID).toBe("local-room");
});
it("redacts provider fields and issued credentials, including unknown integrations", () => {
const settings = configuredSettings();
settings.P2P_managedType = "private-token";
redactTurnSettingsForReport(settings);
expect([settings.P2P_managedType, settings.P2P_managedId, settings.P2P_managedToken]).toEqual([
"redacted",
"redacted",
"redacted",
]);
});
it("omits the whole managed profile group from Markdown, including inactive sources", () => {
const settings = configuredSettings();
settings.P2P_managedType = "";
expect(hasManagedTurnSettings(settings)).toBe(true);
omitManagedTurnProfilesFromMarkdown(settings);
expect(JSON.stringify(settings)).not.toMatch(/private-token|private-key-id|sls\+p2p/);
expect(settings).not.toHaveProperty("remoteConfigurations");
expect(settings).not.toHaveProperty("activeConfigurationId");
expect(settings).not.toHaveProperty("P2P_ActiveRemoteConfigurationId");
});
it("preserves existing profiles and both selections when Markdown omits the group", () => {
const current = configuredSettings();
const incoming = { ...DEFAULT_SETTINGS };
delete (incoming as Partial<typeof incoming>).remoteConfigurations;
delete (incoming as Partial<typeof incoming>).P2P_managedType;
const merged = { ...DEFAULT_SETTINGS, ...incoming };
preserveManagedTurnProfilesOnMarkdownImport(incoming, current, merged);
expect(merged.remoteConfigurations).toEqual(current.remoteConfigurations);
expect(merged.remoteConfigurations).not.toBe(current.remoteConfigurations);
expect(merged.P2P_managedToken).toEqual(current.P2P_managedToken);
expect(merged.activeConfigurationId).toBe("central");
expect(merged.P2P_ActiveRemoteConfigurationId).toBe("managed");
});
it("retains the manual-only Markdown contract", () => {
const settings = { ...DEFAULT_SETTINGS };
const before = structuredClone(settings);
omitManagedTurnProfilesFromMarkdown(settings);
expect(settings).toEqual(before);
});
});