feat: integrate adaptive journal synchronisation

This commit is contained in:
vorotamoroz
2026-07-31 11:28:58 +00:00
parent 0ad71ccecb
commit 81d2e2b815
7 changed files with 153 additions and 33 deletions
+27 -2
View File
@@ -9,7 +9,10 @@ import {
type EntryMilestoneInfo,
type EntryDoc,
} from "@vrtmrz/livesync-commonlib/compat/common/types";
import { isJournalRemoteType } from "@vrtmrz/livesync-commonlib/journal-storage";
import {
isJournalRemoteType,
journalProtocolConfigurationForSettings,
} from "@vrtmrz/livesync-commonlib/journal-storage";
import { ConnectionStringParser } from "@vrtmrz/livesync-commonlib/compat/common/ConnectionString";
import {
activateRemoteConfiguration,
@@ -60,7 +63,29 @@ async function verifyRemoteState(
}
milestone = await dbRet.db.get(MILESTONE_DOCID);
} else if (isJournalRemoteType(settings.remoteType)) {
milestone = await (replicator as LiveSyncJournalReplicator).client.downloadJson("_00000000-milestone.json");
const journal = replicator as LiveSyncJournalReplicator;
if (journalProtocolConfigurationForSettings(settings).journalFormat === "adaptive-v1") {
if (!(await journal.tryConnectRemote(settings, false))) {
standardIo.writeStderr("[Verification] Adaptive Journal connection or capabilities failed.\n");
return false;
}
const remoteFormat = await journal.client.storage.inspectRemoteFormat?.();
if (remoteFormat !== "adaptive-v1") {
standardIo.writeStderr(
`[Verification] Adaptive Journal repository: ${remoteFormat === "empty" ? "NOT INITIALISED" : "FORMAT MISMATCH"}\n`
);
return false;
}
standardIo.writeStderr("[Verification] Adaptive Journal repository: READY\n");
standardIo.writeStderr("[Verification] Legacy remote lock milestone: NOT USED\n");
return true;
}
const client = journal.client;
if (!("downloadJson" in client) || typeof client.downloadJson !== "function") {
standardIo.writeStderr("[Verification] Journal data format changed during verification.\n");
return false;
}
milestone = await client.downloadJson("_00000000-milestone.json");
}
if (milestone) {
+55 -1
View File
@@ -748,7 +748,27 @@ describe("runCommand abnormal cases", () => {
locked: false,
accepted_nodes: ["test-node-id"],
}));
core.services.setting.currentSettings().remoteType = remoteType;
const settings = core.services.setting.currentSettings();
settings.remoteType = remoteType;
if (remoteType === REMOTE_WEBDAV) {
settings.webDAVactiveConnectionURI = serialiseWebDAVConnectionURI({
customHeaders: "",
endpoint: "https://dav.example/vault",
password: "webdav-pass",
prefix: "journal/",
useCustomRequestHandler: false,
username: "webdav-user",
});
} else {
settings.postgrestActiveConnectionURI = serialisePostgRESTConnectionURI({
bearerToken: "signed-token",
customHeaders: "",
endpoint: "https://journal.example",
schema: "livesync_api",
useCustomRequestHandler: false,
vaultId: "vault-1",
});
}
core.services.replicator.getActiveReplicator.mockReturnValue({
nodeid: "test-node-id",
initializeDatabaseForReplication: vi.fn(async () => {}),
@@ -765,6 +785,40 @@ describe("runCommand abnormal cases", () => {
}
);
it("verifies an Adaptive Journal repository without a legacy milestone", async () => {
const core = createCoreMock();
const settings = core.services.setting.currentSettings();
settings.remoteType = REMOTE_WEBDAV;
settings.webDAVactiveConnectionURI = serialiseWebDAVConnectionURI({
customHeaders: "",
endpoint: "https://dav.example/vault",
journalFormat: "adaptive-v1",
password: "webdav-pass",
prefix: "journal/",
useCustomRequestHandler: false,
username: "webdav-user",
});
const inspectRemoteFormat = vi.fn(async () => "adaptive-v1" as const);
const tryConnectRemote = vi.fn(async () => true);
core.services.replicator.getActiveReplicator.mockReturnValue({
client: {
storage: { inspectRemoteFormat },
},
initializeDatabaseForReplication: vi.fn(async () => {}),
nodeid: "test-node-id",
tryConnectRemote,
});
const result = await runCommand(makeOptions("mark-resolved", []), {
...context,
core,
});
expect(result).toBe(true);
expect(tryConnectRemote).toHaveBeenCalledWith(settings, false);
expect(inspectRemoteFormat).toHaveBeenCalledOnce();
});
it("mark-resolved without args runs on active database", async () => {
const core = createCoreMock();
const result = await runCommand(makeOptions("mark-resolved", []), {