feat: preselect adaptive repository identity

This commit is contained in:
vorotamoroz
2026-08-02 07:48:33 +00:00
parent dd8c795210
commit 9715d44fb6
2 changed files with 85 additions and 2 deletions
+31 -2
View File
@@ -5,6 +5,7 @@ import {
LOG_LEVEL_VERBOSE,
} from "@vrtmrz/livesync-commonlib/compat/common/types";
import { createNewVaultSettings } from "@vrtmrz/livesync-commonlib/settings";
import { generateAdaptiveJournalRepositoryIdV1 } from "@vrtmrz/livesync-commonlib/adaptive-journal";
import {
defaultRemoteProviderRegistry,
upsertRemoteConfigurationInPlace,
@@ -71,6 +72,29 @@ export const enum UserMode {
Update = "unknown", // Alias for Unknown for better readability
}
type AdaptiveJournalIdentitySetting = {
expectedRepositoryId?: string;
journalFormat?: string;
};
async function prepareAdaptiveRepositoryIdentityForSetup<T extends object>(
settings: T,
userMode: UserMode
): Promise<T> {
const adaptiveSettings = settings as T & AdaptiveJournalIdentitySetting;
if (
userMode !== UserMode.NewUser ||
adaptiveSettings.journalFormat !== "adaptive-v1" ||
(adaptiveSettings.expectedRepositoryId ?? "").trim() !== ""
) {
return settings;
}
return {
...settings,
expectedRepositoryId: await generateAdaptiveJournalRepositoryIdV1(),
};
}
/**
* Setup Manager to handle onboarding and configuration setup
*/
@@ -210,10 +234,15 @@ export class SetupManager extends AbstractModule {
}
const newSetting = copySettingsForRemoteProfileUpdate(currentSetting);
const preparedSettings = await prepareAdaptiveRepositoryIdentityForSetup(configuration.settings, userMode);
const preparedConfiguration = {
...configuration,
settings: preparedSettings,
} as BuiltInRemoteConfiguration;
if (activate) {
defaultRemoteProviderRegistry.applyConfiguration(newSetting, configuration);
defaultRemoteProviderRegistry.applyConfiguration(newSetting, preparedConfiguration);
} else {
Object.assign(newSetting, configuration.settings);
Object.assign(newSetting, preparedSettings);
}
const activateForP2P = defaultRemoteProviderRegistry.supportsActivationRole(type, "p2p");
@@ -462,6 +462,60 @@ describe("SetupManager", () => {
expect(nextSettings).toEqual(expect.objectContaining({ ...bucketSettings, remoteType: REMOTE_MINIO }));
});
it("preselects a repository identity during fresh Adaptive Object Storage onboarding", async () => {
const { manager, setting, dialogManager } = createSetupManager();
dialogManager.openWithExplicitCancel
.mockResolvedValueOnce({
endpoint: "https://storage.example",
accessKey: "key",
secretKey: "secret",
bucket: "notes",
region: "auto",
bucketPrefix: "",
useCustomRequestHandler: false,
bucketCustomHeaders: "",
forcePathStyle: true,
expectedRepositoryId: "",
journalFormat: "adaptive-v1",
packReadPolicy: "whole-pack",
})
.mockResolvedValueOnce(true);
await manager.onBucketManualSetup(UserMode.NewUser, setting.currentSettings());
const current = setting.currentSettings();
expect(current.expectedRepositoryId).toMatch(/^[A-Za-z0-9_-]{43}$/u);
const activeProfile = current.remoteConfigurations[current.activeConfigurationId];
expect(activeProfile?.uri).toContain(`expectedRepositoryId=${current.expectedRepositoryId}`);
});
it("leaves an existing-device Adaptive Object Storage attachment on trust on first use", async () => {
const { manager, setting, dialogManager } = createSetupManager();
dialogManager.openWithExplicitCancel
.mockResolvedValueOnce({
endpoint: "https://storage.example",
accessKey: "key",
secretKey: "secret",
bucket: "notes",
region: "auto",
bucketPrefix: "",
useCustomRequestHandler: false,
bucketCustomHeaders: "",
forcePathStyle: true,
expectedRepositoryId: "",
journalFormat: "adaptive-v1",
packReadPolicy: "whole-pack",
})
.mockResolvedValueOnce(true);
await manager.onBucketManualSetup(UserMode.ExistingUser, setting.currentSettings());
const current = setting.currentSettings();
expect(current.expectedRepositoryId).toBe("");
const activeProfile = current.remoteConfigurations[current.activeConfigurationId];
expect(activeProfile?.uri).not.toContain("expectedRepositoryId=");
});
it("creates and selects a P2P profile during fresh manual onboarding", async () => {
const { manager, setting, dialogManager } = createSetupManager();
setting.settings = {