@vrtmrz/livesync-commonlib 0.1.23 → 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/API/processSetting.d.ts +1 -1
  2. package/dist/API/processSetting.js +10 -6
  3. package/dist/common/ConnectionString.js +15 -8
  4. package/dist/common/models/setting.const.qr.js +5 -0
  5. package/dist/common/models/setting.lifecycle.js +5 -3
  6. package/dist/common/models/setting.p2p.d.ts +10 -0
  7. package/dist/common/models/setting.p2p.js +13 -0
  8. package/dist/common/models/setting.type.d.ts +10 -0
  9. package/dist/common/models/tweak.compatibility.d.ts +34 -0
  10. package/dist/common/models/tweak.compatibility.js +110 -0
  11. package/dist/common/models/tweak.definition.d.ts +110 -19
  12. package/dist/common/models/tweak.definition.js +62 -29
  13. package/dist/common/settingConstants.d.ts +5 -0
  14. package/dist/common/types.d.ts +6 -3
  15. package/dist/common/types.js +6 -0
  16. package/dist/common/utils.js +4 -1
  17. package/dist/p2p/P2PService.d.ts +7 -1
  18. package/dist/p2p/P2PService.js +13 -7
  19. package/dist/p2p/index.d.ts +3 -1
  20. package/dist/p2p/index.js +6 -0
  21. package/dist/pouchdb/LiveSyncDBFunctions.d.ts +3 -3
  22. package/dist/pouchdb/LiveSyncDBFunctions.js +9 -15
  23. package/dist/replication/CentralCompatibility.d.ts +4 -2
  24. package/dist/replication/CentralCompatibility.js +5 -3
  25. package/dist/replication/couchdb/LiveSyncReplicator.js +10 -2
  26. package/dist/replication/journal/LiveSyncJournalReplicator.d.ts +2 -2
  27. package/dist/replication/journal/LiveSyncJournalReplicator.js +18 -4
  28. package/dist/replication/trystero/P2PRoomSessionOwner.d.ts +22 -1
  29. package/dist/replication/trystero/P2PRoomSessionOwner.js +193 -13
  30. package/dist/replication/trystero/TrysteroReplicator.js +12 -7
  31. package/dist/replication/trystero/TrysteroReplicatorP2PServer.d.ts +1 -0
  32. package/dist/replication/trystero/TrysteroReplicatorP2PServer.js +10 -3
  33. package/dist/replication/trystero/p2pReplicatorConfigurationIdentity.js +6 -3
  34. package/dist/replication/trystero/useP2PReplicatorFeature.d.ts +6 -1
  35. package/dist/replication/trystero/useP2PReplicatorFeature.js +7 -4
  36. package/dist/rpc/transports/trysteroUtils.d.ts +2 -2
  37. package/dist/rpc/transports/trysteroUtils.js +32 -2
  38. package/dist/serviceFeatures/remoteConfig.js +3 -0
  39. package/dist/services/base/IService.d.ts +3 -3
  40. package/dist/services/base/ReplicationService.d.ts +2 -2
  41. package/dist/services/base/ReplicationService.js +14 -11
  42. package/dist/services/base/SettingService.d.ts +1 -0
  43. package/dist/services/base/SettingService.js +37 -9
  44. package/dist/services/base/TweakValueService.d.ts +5 -3
  45. package/dist/services/implements/injectable/InjectableTweakValueService.d.ts +5 -5
  46. package/dist/settings.d.ts +3 -0
  47. package/dist/settings.js +2 -0
  48. package/dist/worker/bgWorker.js +1 -1
  49. package/docs/development.md +3 -3
  50. package/docs/p2p-transport-lifecycle.md +86 -4
  51. package/docs/proven-in-use.md +32 -0
  52. package/docs/settings-lifecycle.md +20 -1
  53. package/package.json +1 -1
@@ -37,5 +37,5 @@ type ErasureProperties = keyof ObsidianLiveSyncSettings;
37
37
  * @returns Generated setup URI
38
38
  */
39
39
  export declare function encodeSettingsToSetupURI(settingString: ObsidianLiveSyncSettings, passphrase: string, removeProperties?: ErasureProperties[], skipDefaultValue?: boolean): Promise<string>;
40
- export declare function decodeSettingsFromSetupURI(uri: string, passphrase: string): Promise<false | ObsidianLiveSyncSettings>;
40
+ export declare function decodeSettingsFromSetupURI(uri: string, passphrase: string): Promise<false | Omit<ObsidianLiveSyncSettings, "P2P_iceServers" | "P2P_iceServersExpiresAt">>;
41
41
  export {};
@@ -4,11 +4,13 @@ import { decodeAnyArray, encodeAnyArray } from "octagonal-wheels/object";
4
4
  import {
5
5
  DEFAULT_SETTINGS,
6
6
  KeyIndexOfSettings,
7
- LOG_LEVEL_NOTICE
7
+ LOG_LEVEL_NOTICE,
8
+ omitP2PRuntimeSettings
8
9
  } from "../common/types.js";
9
10
  import { decryptString, encryptString } from "../encryption/stringEncryption.js";
10
11
  import { LOG_LEVEL_VERBOSE, Logger } from "octagonal-wheels/common/logger";
11
12
  function encodeSettingsToQRCodeData(settings) {
13
+ settings = omitP2PRuntimeSettings(settings);
12
14
  const fullIndexes = Object.entries(KeyIndexOfSettings);
13
15
  let maxIndex = 0;
14
16
  for (const [, index] of fullIndexes) {
@@ -48,7 +50,7 @@ function decodeSettingsFromQRCodeData(qr) {
48
50
  LOG_LEVEL_VERBOSE
49
51
  );
50
52
  }
51
- return newSettings;
53
+ return omitP2PRuntimeSettings(newSettings);
52
54
  }
53
55
  var OutputFormat = /* @__PURE__ */ ((OutputFormat2) => {
54
56
  OutputFormat2[OutputFormat2["SVG"] = 0] = "SVG";
@@ -99,8 +101,11 @@ const necessaryErasureProperties = [
99
101
  ];
100
102
  async function encodeSettingsToSetupURI(settingString, passphrase, removeProperties = ["pluginSyncExtendedSetting"], skipDefaultValue = false) {
101
103
  const setting = {
102
- ...settingString
104
+ ...omitP2PRuntimeSettings(settingString)
103
105
  };
106
+ delete setting.P2P_managedType;
107
+ delete setting.P2P_managedId;
108
+ delete setting.P2P_managedToken;
104
109
  if (skipDefaultValue) {
105
110
  const keys = Object.keys(setting);
106
111
  for (const k of keys) {
@@ -123,10 +128,9 @@ async function decodeSettingsFromSetupURI(uri, passphrase) {
123
128
  const encryptedSetting = uri.substring(configURIBase.length);
124
129
  const decrypted = await decryptString(decodeURIComponent(encryptedSetting), passphrase);
125
130
  try {
126
- return JSON.parse(decrypted);
127
- } catch (e) {
131
+ return omitP2PRuntimeSettings(JSON.parse(decrypted));
132
+ } catch {
128
133
  Logger(`Failed to parse settings from decrypted data`, LOG_LEVEL_NOTICE);
129
- Logger(e, LOG_LEVEL_VERBOSE);
130
134
  return false;
131
135
  }
132
136
  }
@@ -1,9 +1,12 @@
1
- import { normaliseP2PConnectionPath, normaliseP2PMaxWirePayloadBytes } from "./models/setting.p2p.js";
1
+ import {
2
+ normaliseP2PConnectionPath,
3
+ normaliseP2PMaxWirePayloadBytes
4
+ } from "./models/setting.p2p.js";
2
5
  const PROXY_SCHEME = "https";
3
6
  function parseSlsUri(uriString) {
4
7
  const match = uriString.match(/^sls\+([^:]+):(.*)$/);
5
8
  if (!match) {
6
- throw new Error(`Unsupported URI: ${uriString}`);
9
+ throw new Error("Unsupported URI");
7
10
  }
8
11
  const subscheme = match[1];
9
12
  const rest = match[2];
@@ -20,7 +23,7 @@ class ConnectionStringParser {
20
23
  static parse(uriString) {
21
24
  const match = uriString.match(/^sls\+([^:]+):/);
22
25
  if (!match) {
23
- throw new Error(`Unsupported URI: ${uriString}`);
26
+ throw new Error("Unsupported URI");
24
27
  }
25
28
  const subscheme = match[1];
26
29
  if (subscheme === "p2p") {
@@ -43,7 +46,7 @@ class ConnectionStringParser {
43
46
  settings: this.parseS3(url)
44
47
  };
45
48
  default:
46
- throw new Error(`Unsupported protocol: sls+${subscheme}`);
49
+ throw new Error("Unsupported protocol");
47
50
  }
48
51
  }
49
52
  /**
@@ -126,9 +129,7 @@ class ConnectionStringParser {
126
129
  }
127
130
  static parseP2P(uriString) {
128
131
  const match = uriString.match(/^sls\+p2p:\/\/([^?#]+)(?:\?([^#]*))?(?:#(.*))?$/);
129
- if (!match) {
130
- throw new Error(`Invalid P2P URI: ${uriString}`);
131
- }
132
+ if (!match) throw new Error("Invalid P2P URI");
132
133
  const authority = match[1];
133
134
  const queryString = match[2] || "";
134
135
  let userinfo = "";
@@ -158,7 +159,10 @@ class ConnectionStringParser {
158
159
  P2P_turnUsername: searchParams.get("turnUser") || "",
159
160
  P2P_turnCredential: searchParams.get("turnPass") || "",
160
161
  P2P_maxWirePayloadBytes: normaliseP2PMaxWirePayloadBytes(Number(searchParams.get("maxWirePayloadBytes"))),
161
- P2P_connectionPath: normaliseP2PConnectionPath(searchParams.get("connectionPath"))
162
+ P2P_connectionPath: normaliseP2PConnectionPath(searchParams.get("connectionPath")),
163
+ P2P_managedType: searchParams.get("managedType") || void 0,
164
+ P2P_managedId: searchParams.get("managedId") || void 0,
165
+ P2P_managedToken: searchParams.get("token") || void 0
162
166
  };
163
167
  }
164
168
  static serializeP2P(settings) {
@@ -176,6 +180,9 @@ class ConnectionStringParser {
176
180
  String(normaliseP2PMaxWirePayloadBytes(settings.P2P_maxWirePayloadBytes))
177
181
  );
178
182
  searchParams.set("connectionPath", normaliseP2PConnectionPath(settings.P2P_connectionPath));
183
+ if (settings.P2P_managedType) searchParams.set("managedType", settings.P2P_managedType);
184
+ if (settings.P2P_managedId) searchParams.set("managedId", settings.P2P_managedId);
185
+ if (settings.P2P_managedToken) searchParams.set("token", settings.P2P_managedToken);
179
186
  const credentials = settings.P2P_passphrase ? `:${encodeURIComponent(settings.P2P_passphrase)}@` : "";
180
187
  const host = encodeURIComponent(settings.P2P_roomID);
181
188
  const query = searchParams.toString() ? `?${searchParams.toString()}` : "";
@@ -159,6 +159,11 @@ const KeyIndexOfSettings = {
159
159
  P2P_turnServers: 150,
160
160
  P2P_turnUsername: 151,
161
161
  P2P_turnCredential: 152,
162
+ P2P_managedType: -1,
163
+ P2P_managedId: -1,
164
+ P2P_managedToken: -1,
165
+ P2P_iceServers: -1,
166
+ P2P_iceServersExpiresAt: -1,
162
167
  syncInternalFileOverwritePatterns: 153,
163
168
  useOnlyLocalChunk: 154,
164
169
  maxMTimeForReflectEvents: 155,
@@ -4,6 +4,7 @@ import {
4
4
  SETTING_VERSION_INITIAL,
5
5
  SETTING_VERSION_SUPPORT_CASE_INSENSITIVE
6
6
  } from "./setting.const.js";
7
+ import { omitP2PRuntimeSettings } from "./setting.p2p.js";
7
8
  const SettingsMigrationReviewCodes = {
8
9
  LegacyUpdatePending: "legacy-update-review-pending",
9
10
  FutureSchema: "settings-schema-newer-than-runtime",
@@ -22,18 +23,19 @@ const SETTINGS_MIGRATIONS = [
22
23
  }
23
24
  ];
24
25
  function cloneSettings(source, fallbacks) {
26
+ const persistableSource = omitP2PRuntimeSettings(source);
25
27
  return {
26
28
  ...fallbacks,
27
- ...source,
29
+ ...persistableSource,
28
30
  remoteConfigurations: Object.fromEntries(
29
- Object.entries(source.remoteConfigurations ?? fallbacks.remoteConfigurations).map(([id, config]) => [
31
+ Object.entries(persistableSource.remoteConfigurations ?? fallbacks.remoteConfigurations).map(([id, config]) => [
30
32
  id,
31
33
  { ...config }
32
34
  ])
33
35
  ),
34
36
  pluginSyncExtendedSetting: {
35
37
  ...fallbacks.pluginSyncExtendedSetting,
36
- ...source.pluginSyncExtendedSetting
38
+ ...persistableSource.pluginSyncExtendedSetting
37
39
  }
38
40
  };
39
41
  }
@@ -1,4 +1,14 @@
1
1
  import { type P2PConnectionPath } from "./setting.const.js";
2
+ import type { P2PConnectionInfo, P2PSyncSetting } from "./setting.type.js";
3
+ /** Report whether the selected P2P settings request host-managed TURN credentials. */
4
+ export declare function hasManagedP2PTurnConfiguration(settings: Partial<Pick<P2PConnectionInfo, "P2P_managedType">>): boolean;
5
+ /** Remove connection-only ICE credentials before settings cross a serialisation boundary. */
6
+ export declare function omitP2PRuntimeSettings<T extends Partial<P2PSyncSetting>>(settings: T): Omit<T, "P2P_iceServers" | "P2P_iceServersExpiresAt">;
7
+ /**
8
+ * Report whether a P2P profile has a usable manual TURN endpoint or requests
9
+ * host-managed TURN credentials. STUN-only profiles remain false.
10
+ */
11
+ export declare function hasP2PTurnConfiguration(settings: Partial<Pick<P2PConnectionInfo, "P2P_turnServers" | "P2P_managedType">>): boolean;
2
12
  /**
3
13
  * Return a safe outgoing RPC wire-payload bound for Trystero.
4
14
  *
@@ -1,4 +1,14 @@
1
1
  import { P2PConnectionPaths, P2PMessageSizePresets } from "./setting.const.js";
2
+ function hasManagedP2PTurnConfiguration(settings) {
3
+ return typeof settings.P2P_managedType === "string" && settings.P2P_managedType.trim().length > 0;
4
+ }
5
+ function omitP2PRuntimeSettings(settings) {
6
+ const { P2P_iceServers: _iceServers, P2P_iceServersExpiresAt: _expiresAt, ...persistable } = settings;
7
+ return persistable;
8
+ }
9
+ function hasP2PTurnConfiguration(settings) {
10
+ return hasManagedP2PTurnConfiguration(settings) || typeof settings.P2P_turnServers === "string" && hasValidP2PTurnServerUrl(settings.P2P_turnServers);
11
+ }
2
12
  function normaliseP2PMaxWirePayloadBytes(value) {
3
13
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < P2PMessageSizePresets.MaximumCompatibility || value > P2PMessageSizePresets.Standard) {
4
14
  return P2PMessageSizePresets.Standard;
@@ -31,10 +41,13 @@ function hasValidP2PTurnServerUrl(value) {
31
41
  return splitP2PTurnServerUrls(value).some(isValidP2PTurnServerUrl);
32
42
  }
33
43
  export {
44
+ hasManagedP2PTurnConfiguration,
45
+ hasP2PTurnConfiguration,
34
46
  hasValidP2PTurnServerUrl,
35
47
  isValidP2PTurnServerUrl,
36
48
  normaliseP2PConnectionPath,
37
49
  normaliseP2PMaxWirePayloadBytes,
50
+ omitP2PRuntimeSettings,
38
51
  splitP2PRelayUrls,
39
52
  splitP2PTurnServerUrls
40
53
  };
@@ -528,6 +528,12 @@ export interface P2PConnectionInfo {
528
528
  * The TURN credential (password, secret, etc...) for the P2P connection.
529
529
  */
530
530
  P2P_turnCredential: string;
531
+ /** Host-defined managed TURN provider type. */
532
+ P2P_managedType?: string;
533
+ /** Host-defined managed TURN provider identifier. */
534
+ P2P_managedId?: string;
535
+ /** Host-defined managed TURN provider token. */
536
+ P2P_managedToken?: string;
531
537
  /**
532
538
  * Maximum serialised RPC wire payload sent through Trystero before
533
539
  * Commonlib splits it. Applies to outgoing messages.
@@ -552,6 +558,10 @@ export interface P2PSyncSetting extends P2PConnectionInfo {
552
558
  P2P_AutoAcceptingPeers: string;
553
559
  P2P_AutoDenyingPeers: string;
554
560
  P2P_IsHeadless?: boolean;
561
+ /** ICE servers prepared for one room connection. Never persist or share this value. */
562
+ P2P_iceServers?: readonly RTCIceServer[];
563
+ /** Absolute Unix timestamp in milliseconds for the prepared ICE servers. */
564
+ P2P_iceServersExpiresAt?: number;
555
565
  }
556
566
  /**
557
567
  * Interface representing the settings for a remote type.
@@ -0,0 +1,34 @@
1
+ import { type TweakReconstruction, type TweakValues } from "./tweak.definition.js";
2
+ export type TweakAssessmentRelation = "equal" | "different" | "unadvertised";
3
+ export interface TweakAssessmentValue {
4
+ readonly present: boolean;
5
+ readonly rawValue: TweakValues[keyof TweakValues];
6
+ readonly effectiveValue: TweakValues[keyof TweakValues];
7
+ }
8
+ export interface TweakAssessmentEntry {
9
+ readonly key: keyof TweakValues;
10
+ readonly current: TweakAssessmentValue;
11
+ readonly preferred: TweakAssessmentValue;
12
+ readonly relation: TweakAssessmentRelation;
13
+ }
14
+ export interface TweakTransitionReason {
15
+ readonly key: keyof TweakValues;
16
+ readonly reconstruction: Exclude<TweakReconstruction, "none">;
17
+ }
18
+ export interface TweakTransition {
19
+ readonly changes: Readonly<TweakValues>;
20
+ readonly reconstruction: TweakReconstruction;
21
+ readonly reasons: readonly TweakTransitionReason[];
22
+ }
23
+ export interface TweakAssessment {
24
+ readonly alignment: "matched" | "mismatched";
25
+ readonly representationDiffers: boolean;
26
+ readonly entries: readonly TweakAssessmentEntry[];
27
+ readonly adoptPreferred: TweakTransition;
28
+ readonly adoptCurrent: TweakTransition;
29
+ readonly onlyCompatibleLossyDifferences: boolean;
30
+ readonly currentValues: Readonly<TweakValues>;
31
+ readonly preferredValues: Readonly<TweakValues>;
32
+ }
33
+ /** Assess the semantic and stored-representation relationship between two tweak snapshots. */
34
+ export declare function assessTweakCompatibility(current: Readonly<TweakValues>, preferred: Readonly<TweakValues>): TweakAssessment;
@@ -0,0 +1,110 @@
1
+ import {
2
+ TweakCompatibilityRules,
3
+ TweakValuesTemplate
4
+ } from "./tweak.definition.js";
5
+ const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
6
+ function snapshotTweakValues(values) {
7
+ const snapshot = {};
8
+ for (const key of Object.keys(TweakValuesTemplate)) {
9
+ if (hasOwn(values, key)) snapshot[key] = values[key];
10
+ }
11
+ return Object.freeze(snapshot);
12
+ }
13
+ function assessedValue(values, key, knownDefault) {
14
+ const present = hasOwn(values, key);
15
+ const rawValue = values[key];
16
+ const effectiveValue = rawValue === void 0 ? knownDefault : rawValue;
17
+ return Object.freeze({ present, rawValue, effectiveValue });
18
+ }
19
+ function highestReconstruction(current, next) {
20
+ if (current === "required" || next === "required") return "required";
21
+ return "recommended";
22
+ }
23
+ function reconstructionForTransition(key, from, to) {
24
+ const rule = TweakCompatibilityRules.find((candidate) => candidate.key === key);
25
+ if (!rule) return "none";
26
+ let reconstruction = rule.reconstruction;
27
+ const extensibleRule = rule;
28
+ for (const pattern of extensibleRule.specificPatterns ?? []) {
29
+ const matchesFrom = hasOwn(pattern, "from") && pattern.from === from;
30
+ const matchesTo = hasOwn(pattern, "to") && pattern.to === to;
31
+ if (matchesFrom || matchesTo) {
32
+ reconstruction = highestReconstruction(reconstruction, pattern.reconstruction);
33
+ }
34
+ }
35
+ return reconstruction;
36
+ }
37
+ function transition(entries, sourceSide, targetSide) {
38
+ const changes = {};
39
+ const reasons = [];
40
+ let reconstruction = "none";
41
+ for (const entry of entries) {
42
+ const source = entry[sourceSide];
43
+ const target = entry[targetSide];
44
+ const sourceAdvertised = source.present && source.rawValue !== void 0;
45
+ const targetAdvertised = target.present && target.rawValue !== void 0;
46
+ const effectiveValueDiffers = source.effectiveValue !== target.effectiveValue;
47
+ const shouldFillMissingTarget = !targetAdvertised && sourceAdvertised;
48
+ if (source.effectiveValue === void 0 || !effectiveValueDiffers && !shouldFillMissingTarget) continue;
49
+ changes[entry.key] = source.effectiveValue;
50
+ if (entry.relation === "equal") continue;
51
+ const effect = reconstructionForTransition(entry.key, target.effectiveValue, source.effectiveValue);
52
+ if (effect === "none") continue;
53
+ const reason = Object.freeze({
54
+ key: entry.key,
55
+ reconstruction: effect
56
+ });
57
+ reasons.push(reason);
58
+ reconstruction = highestReconstruction(reconstruction, reason.reconstruction);
59
+ }
60
+ return Object.freeze({
61
+ changes: Object.freeze(changes),
62
+ reconstruction,
63
+ reasons: Object.freeze(reasons)
64
+ });
65
+ }
66
+ function assessTweakCompatibility(current, preferred) {
67
+ const currentValues = snapshotTweakValues(current);
68
+ const preferredValues = snapshotTweakValues(preferred);
69
+ let representationDiffers = false;
70
+ const entries = TweakCompatibilityRules.map((rule) => {
71
+ const knownDefault = "knownDefault" in rule ? rule.knownDefault : void 0;
72
+ const currentValue = assessedValue(currentValues, rule.key, knownDefault);
73
+ const preferredValue = assessedValue(preferredValues, rule.key, knownDefault);
74
+ const currentAdvertised = currentValue.present && currentValue.rawValue !== void 0;
75
+ const preferredAdvertised = preferredValue.present && preferredValue.rawValue !== void 0;
76
+ let relation;
77
+ if ((!currentAdvertised || !preferredAdvertised) && knownDefault === void 0) {
78
+ relation = "unadvertised";
79
+ } else {
80
+ relation = currentValue.effectiveValue === preferredValue.effectiveValue ? "equal" : "different";
81
+ }
82
+ if (currentValue.present !== preferredValue.present || currentValue.rawValue !== preferredValue.rawValue) {
83
+ representationDiffers = true;
84
+ }
85
+ return Object.freeze({
86
+ key: rule.key,
87
+ current: currentValue,
88
+ preferred: preferredValue,
89
+ relation
90
+ });
91
+ });
92
+ const frozenEntries = Object.freeze(entries);
93
+ const differences = frozenEntries.filter(({ relation }) => relation === "different");
94
+ const compatibleLossyKeys = new Set(
95
+ TweakCompatibilityRules.filter((rule) => "compatibleLossyOrder" in rule).map(({ key }) => key)
96
+ );
97
+ return Object.freeze({
98
+ alignment: differences.length === 0 ? "matched" : "mismatched",
99
+ representationDiffers,
100
+ entries: frozenEntries,
101
+ adoptPreferred: transition(frozenEntries, "preferred", "current"),
102
+ adoptCurrent: transition(frozenEntries, "current", "preferred"),
103
+ onlyCompatibleLossyDifferences: differences.length > 0 && differences.every(({ key }) => compatibleLossyKeys.has(key)) && !frozenEntries.some(({ relation }) => relation === "unadvertised"),
104
+ currentValues,
105
+ preferredValues
106
+ });
107
+ }
108
+ export {
109
+ assessTweakCompatibility
110
+ };
@@ -1,5 +1,91 @@
1
1
  import type { ObsidianLiveSyncSettings } from "./setting.type.js";
2
- export declare const TweakValuesShouldMatchedTemplate: Partial<ObsidianLiveSyncSettings>;
2
+ export type TweakReconstruction = "none" | "recommended" | "required";
3
+ /**
4
+ * Single source for tweak comparison semantics and the maintained legacy
5
+ * compatibility projections below.
6
+ */
7
+ export declare const TweakCompatibilityRules: readonly [{
8
+ readonly key: "minimumChunkSize";
9
+ readonly templateValue: 20;
10
+ readonly reconstruction: "none";
11
+ }, {
12
+ readonly key: "longLineThreshold";
13
+ readonly templateValue: 250;
14
+ readonly reconstruction: "none";
15
+ }, {
16
+ readonly key: "encrypt";
17
+ readonly templateValue: false;
18
+ readonly reconstruction: "required";
19
+ }, {
20
+ readonly key: "usePathObfuscation";
21
+ readonly templateValue: false;
22
+ readonly reconstruction: "required";
23
+ }, {
24
+ readonly key: "enableCompression";
25
+ readonly templateValue: false;
26
+ readonly reconstruction: "none";
27
+ }, {
28
+ readonly key: "useEden";
29
+ readonly templateValue: false;
30
+ readonly reconstruction: "none";
31
+ }, {
32
+ readonly key: "customChunkSize";
33
+ readonly templateValue: 0;
34
+ readonly reconstruction: "recommended";
35
+ readonly compatibleLossyOrder: 1;
36
+ }, {
37
+ readonly key: "useDynamicIterationCount";
38
+ readonly templateValue: false;
39
+ readonly reconstruction: "required";
40
+ }, {
41
+ readonly key: "hashAlg";
42
+ readonly templateValue: "xxhash64";
43
+ readonly reconstruction: "recommended";
44
+ readonly compatibleLossyOrder: 0;
45
+ }, {
46
+ readonly key: "enableChunkSplitterV2";
47
+ readonly templateValue: false;
48
+ readonly reconstruction: "none";
49
+ }, {
50
+ readonly key: "maxChunksInEden";
51
+ readonly templateValue: 10;
52
+ readonly reconstruction: "none";
53
+ }, {
54
+ readonly key: "maxTotalLengthInEden";
55
+ readonly templateValue: 1024;
56
+ readonly reconstruction: "none";
57
+ }, {
58
+ readonly key: "maxAgeInEden";
59
+ readonly templateValue: 10;
60
+ readonly reconstruction: "none";
61
+ }, {
62
+ readonly key: "usePluginSyncV2";
63
+ readonly templateValue: false;
64
+ readonly reconstruction: "none";
65
+ readonly knownDefault: false;
66
+ }, {
67
+ readonly key: "handleFilenameCaseSensitive";
68
+ readonly templateValue: false;
69
+ readonly reconstruction: "required";
70
+ readonly knownDefault: false;
71
+ }, {
72
+ readonly key: "useSegmenter";
73
+ readonly templateValue: false;
74
+ readonly reconstruction: "none";
75
+ }, {
76
+ readonly key: "E2EEAlgorithm";
77
+ readonly templateValue: "v2";
78
+ readonly reconstruction: "none";
79
+ readonly knownDefault: import("./setting.type.js").E2EEAlgorithm;
80
+ }, {
81
+ readonly key: "chunkSplitterVersion";
82
+ readonly templateValue: "v3-rabin-karp";
83
+ readonly reconstruction: "recommended";
84
+ readonly knownDefault: import("./setting.type.js").ChunkSplitterVersion;
85
+ readonly compatibleLossyOrder: 2;
86
+ }];
87
+ export type TweakComparedKey = (typeof TweakCompatibilityRules)[number]["key"];
88
+ export declare const TweakValuesShouldMatchedTemplate: Pick<ObsidianLiveSyncSettings, TweakComparedKey>;
3
89
  type TweakKeys = keyof TweakValues;
4
90
  export declare const IncompatibleChanges: TweakKeys[];
5
91
  export declare const CompatibleButLossyChanges: TweakKeys[];
@@ -19,6 +105,24 @@ export declare const TweakValuesRecommendedTemplate: Partial<ObsidianLiveSyncSet
19
105
  export declare const TweakValuesDefault: Partial<ObsidianLiveSyncSettings>;
20
106
  export declare const TweakValuesTemplate: {
21
107
  tweakModified: number;
108
+ usePluginSyncV2: boolean;
109
+ encrypt: boolean;
110
+ usePathObfuscation: boolean;
111
+ E2EEAlgorithm: import("./setting.type.js").E2EEAlgorithm;
112
+ hashAlg: import("./setting.type.js").HashAlgorithm;
113
+ minimumChunkSize: number;
114
+ customChunkSize: number;
115
+ longLineThreshold: number;
116
+ useSegmenter: boolean;
117
+ enableChunkSplitterV2: boolean;
118
+ chunkSplitterVersion: import("./setting.type.js").ChunkSplitterVersion;
119
+ useEden: boolean;
120
+ maxChunksInEden: number;
121
+ maxTotalLengthInEden: number;
122
+ maxAgeInEden: number;
123
+ useDynamicIterationCount: boolean;
124
+ enableCompression: boolean;
125
+ handleFilenameCaseSensitive: boolean;
22
126
  liveSync?: boolean;
23
127
  syncOnSave?: boolean;
24
128
  syncOnStart?: boolean;
@@ -72,7 +176,6 @@ export declare const TweakValuesTemplate: {
72
176
  autoSweepPluginsPeriodic?: boolean;
73
177
  notifyPluginOrSettingUpdated?: boolean;
74
178
  deviceAndVaultName?: string;
75
- usePluginSyncV2?: boolean;
76
179
  usePluginEtc?: boolean;
77
180
  pluginSyncExtendedSetting?: Record<import("./setting.type.js").PluginSyncSettingEntry["key"], import("./setting.type.js").PluginSyncSettingEntry>;
78
181
  useAdvancedMode?: boolean;
@@ -124,34 +227,18 @@ export declare const TweakValuesTemplate: {
124
227
  bucketPrefix?: string;
125
228
  forcePathStyle?: boolean;
126
229
  remoteType?: import("./setting.type.js").RemoteType;
127
- encrypt?: boolean;
128
230
  passphrase?: string;
129
- usePathObfuscation?: boolean;
130
- E2EEAlgorithm?: import("./setting.type.js").E2EEAlgorithm;
131
- hashAlg?: import("./setting.type.js").HashAlgorithm;
132
- minimumChunkSize?: number;
133
- customChunkSize?: number;
134
- longLineThreshold?: number;
135
- useSegmenter?: boolean;
136
- enableChunkSplitterV2?: boolean;
137
231
  doNotUseFixedRevisionForChunks?: boolean;
138
- chunkSplitterVersion?: import("./setting.type.js").ChunkSplitterVersion;
139
- useEden?: boolean;
140
- maxChunksInEden?: number;
141
- maxTotalLengthInEden?: number;
142
- maxAgeInEden?: number;
143
232
  checkIntegrityOnSave?: boolean;
144
233
  useHistory?: boolean;
145
234
  disableRequestURI?: boolean;
146
235
  sendChunksBulk?: boolean;
147
236
  sendChunksBulkMaxSize?: number;
148
- useDynamicIterationCount?: boolean;
149
237
  doNotPaceReplication?: boolean;
150
238
  readChunksOnline?: boolean;
151
239
  useOnlyLocalChunk?: boolean;
152
240
  concurrencyOfReadChunksOnline?: number;
153
241
  minimumIntervalOfReadChunksOnline?: number;
154
- enableCompression?: boolean;
155
242
  batch_size?: number;
156
243
  batches_limit?: number;
157
244
  ignoreVersionCheck?: boolean;
@@ -160,7 +247,6 @@ export declare const TweakValuesTemplate: {
160
247
  hashCacheMaxCount?: number;
161
248
  hashCacheMaxAmount?: number;
162
249
  permitEmptyPassphrase?: boolean;
163
- handleFilenameCaseSensitive?: boolean;
164
250
  checkConflictOnlyOnOpen?: boolean;
165
251
  showMergeDialogOnlyOnActive?: boolean;
166
252
  additionalSuffixOfDatabaseName?: string | undefined;
@@ -175,6 +261,8 @@ export declare const TweakValuesTemplate: {
175
261
  P2P_AutoAcceptingPeers?: string;
176
262
  P2P_AutoDenyingPeers?: string;
177
263
  P2P_IsHeadless?: boolean;
264
+ P2P_iceServers?: readonly RTCIceServer[];
265
+ P2P_iceServersExpiresAt?: number;
178
266
  P2P_Enabled?: boolean;
179
267
  P2P_relays?: string;
180
268
  P2P_roomID?: string;
@@ -186,6 +274,9 @@ export declare const TweakValuesTemplate: {
186
274
  P2P_turnServers?: string;
187
275
  P2P_turnUsername?: string;
188
276
  P2P_turnCredential?: string;
277
+ P2P_managedType?: string;
278
+ P2P_managedId?: string;
279
+ P2P_managedToken?: string;
189
280
  P2P_maxWirePayloadBytes?: number;
190
281
  P2P_connectionPath?: import("./setting.const.js").P2PConnectionPath;
191
282
  P2P_useDiagRTC?: boolean;