@vrtmrz/livesync-commonlib 0.1.19-rc.0 → 0.1.20

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 (114) hide show
  1. package/README.md +5 -1
  2. package/dist/common/models/setting.p2p.d.ts +2 -0
  3. package/dist/common/models/setting.p2p.js +5 -0
  4. package/dist/interfaces/ServiceModule.d.ts +13 -4
  5. package/dist/managers/ChunkFetcher.js +10 -0
  6. package/dist/p2p/P2PService.d.ts +123 -0
  7. package/dist/p2p/P2PService.js +271 -0
  8. package/dist/p2p/index.d.ts +8 -0
  9. package/dist/p2p/index.js +8 -0
  10. package/dist/pouchdb/LiveSyncLocalDB.d.ts +3 -0
  11. package/dist/pouchdb/LiveSyncLocalDB.js +23 -3
  12. package/dist/pouchdb/ReplicatorShim.d.ts +43 -4
  13. package/dist/pouchdb/ReplicatorShim.js +78 -5
  14. package/dist/replication/CentralCompatibility.d.ts +38 -0
  15. package/dist/replication/CentralCompatibility.js +39 -0
  16. package/dist/replication/CentralRemoteAdministration.d.ts +84 -0
  17. package/dist/replication/CentralRemoteAdministration.js +71 -0
  18. package/dist/replication/LiveSyncAbstractReplicator.d.ts +19 -6
  19. package/dist/replication/ProviderCapability.d.ts +32 -0
  20. package/dist/replication/ProviderCapability.js +27 -0
  21. package/dist/replication/RemoteResource.d.ts +85 -0
  22. package/dist/replication/RemoteResource.js +17 -0
  23. package/dist/replication/ReplicatorInstance.d.ts +23 -0
  24. package/dist/replication/ReplicatorProvider.d.ts +249 -0
  25. package/dist/replication/ReplicatorProvider.js +145 -0
  26. package/dist/replication/couchdb/LiveSyncReplicator.d.ts +54 -8
  27. package/dist/replication/couchdb/LiveSyncReplicator.js +411 -158
  28. package/dist/replication/index.d.ts +10 -0
  29. package/dist/replication/index.js +70 -0
  30. package/dist/replication/journal/JournalSyncCore.d.ts +2 -0
  31. package/dist/replication/journal/JournalSyncCore.js +18 -5
  32. package/dist/replication/journal/LiveSyncJournalReplicator.d.ts +38 -10
  33. package/dist/replication/journal/LiveSyncJournalReplicator.js +271 -63
  34. package/dist/replication/journal/LiveSyncJournalReplicatorEnv.d.ts +8 -0
  35. package/dist/replication/journal/objectstore/JournalStorageAdapter.d.ts +2 -0
  36. package/dist/replication/journal/objectstore/MinioStorageAdapter.d.ts +2 -0
  37. package/dist/replication/journal/objectstore/MinioStorageAdapter.js +10 -1
  38. package/dist/replication/trystero/LiveSyncTrysteroReplicator.d.ts +12 -40
  39. package/dist/replication/trystero/LiveSyncTrysteroReplicator.js +52 -152
  40. package/dist/replication/trystero/P2PAutomationCoordinator.d.ts +20 -0
  41. package/dist/replication/trystero/P2PAutomationCoordinator.js +43 -0
  42. package/dist/replication/trystero/P2PConnectionProbeAdmission.d.ts +32 -0
  43. package/dist/replication/trystero/P2PConnectionProbeAdmission.js +10 -0
  44. package/dist/replication/trystero/P2PReplicationWire.d.ts +31 -0
  45. package/dist/replication/trystero/P2PReplicationWire.js +50 -0
  46. package/dist/replication/trystero/P2PRoomSession.d.ts +32 -0
  47. package/dist/replication/trystero/P2PRoomSession.js +101 -0
  48. package/dist/replication/trystero/P2PRoomSessionOwner.d.ts +61 -0
  49. package/dist/replication/trystero/P2PRoomSessionOwner.js +249 -0
  50. package/dist/replication/trystero/TrysteroReplicator.d.ts +88 -36
  51. package/dist/replication/trystero/TrysteroReplicator.js +273 -113
  52. package/dist/replication/trystero/TrysteroReplicatorP2PClient.d.ts +7 -4
  53. package/dist/replication/trystero/TrysteroReplicatorP2PClient.js +21 -14
  54. package/dist/replication/trystero/TrysteroReplicatorP2PServer.d.ts +26 -3
  55. package/dist/replication/trystero/TrysteroReplicatorP2PServer.js +84 -39
  56. package/dist/replication/trystero/UseP2PReplicatorResult.d.ts +10 -6
  57. package/dist/replication/trystero/addP2PEventHandlers.d.ts +8 -12
  58. package/dist/replication/trystero/addP2PEventHandlers.js +19 -19
  59. package/dist/replication/trystero/p2pReplicatorConfigurationIdentity.d.ts +9 -0
  60. package/dist/replication/trystero/p2pReplicatorConfigurationIdentity.js +30 -0
  61. package/dist/replication/trystero/types.d.ts +18 -0
  62. package/dist/replication/trystero/types.js +5 -1
  63. package/dist/replication/trystero/useP2PReplicatorCommands.d.ts +3 -3
  64. package/dist/replication/trystero/useP2PReplicatorCommands.js +6 -8
  65. package/dist/replication/trystero/useP2PReplicatorFeature.d.ts +16 -7
  66. package/dist/replication/trystero/useP2PReplicatorFeature.js +72 -55
  67. package/dist/rpc/RpcRoom.d.ts +15 -1
  68. package/dist/rpc/RpcRoom.js +176 -41
  69. package/dist/rpc/RpcSession.d.ts +3 -1
  70. package/dist/rpc/RpcSession.js +2 -2
  71. package/dist/rpc/index.d.ts +1 -1
  72. package/dist/rpc/transports/trysteroUtils.js +2 -1
  73. package/dist/rpc/types.d.ts +26 -1
  74. package/dist/serviceFeatures/checkRemoteSize.js +5 -2
  75. package/dist/serviceModules/Rebuilder.js +66 -56
  76. package/dist/services/base/AppLifecycleService.d.ts +4 -0
  77. package/dist/services/base/AppLifecycleService.js +4 -0
  78. package/dist/services/base/ControlService.js +0 -4
  79. package/dist/services/base/DatabaseEventService.js +1 -1
  80. package/dist/services/base/IService.d.ts +105 -8
  81. package/dist/services/base/ReadinessEvaluator.d.ts +40 -0
  82. package/dist/services/base/ReadinessEvaluator.js +16 -0
  83. package/dist/services/base/RemoteConnection.d.ts +3 -0
  84. package/dist/services/base/RemoteService.js +2 -2
  85. package/dist/services/base/ReplicationService.d.ts +45 -10
  86. package/dist/services/base/ReplicationService.js +248 -91
  87. package/dist/services/base/ReplicationService.readiness.d.ts +52 -0
  88. package/dist/services/base/ReplicationService.readiness.js +87 -0
  89. package/dist/services/base/ReplicationService.typedReplication.d.ts +83 -0
  90. package/dist/services/base/ReplicationService.typedReplication.js +191 -0
  91. package/dist/services/base/ReplicatorService.activeReplicatorState.d.ts +47 -0
  92. package/dist/services/base/ReplicatorService.activeReplicatorState.js +107 -0
  93. package/dist/services/base/ReplicatorService.centralRemoteAdministration.d.ts +5 -0
  94. package/dist/services/base/ReplicatorService.centralRemoteAdministration.js +44 -0
  95. package/dist/services/base/ReplicatorService.d.ts +75 -14
  96. package/dist/services/base/ReplicatorService.js +232 -53
  97. package/dist/services/base/ReplicatorService.remoteResourceResolver.d.ts +4 -0
  98. package/dist/services/base/ReplicatorService.remoteResourceResolver.js +11 -0
  99. package/dist/services/base/TweakValueService.d.ts +3 -2
  100. package/dist/services/implements/injectable/InjectableTweakValueService.d.ts +1 -1
  101. package/dist/services/lib/HandlerUtils.d.ts +24 -0
  102. package/dist/services/lib/HandlerUtils.js +40 -0
  103. package/docs/development.md +40 -7
  104. package/docs/p2p-transport-lifecycle.md +135 -11
  105. package/docs/proven-in-use.md +5 -1
  106. package/docs/remote-configurations.md +4 -0
  107. package/docs/service-feature-composition.md +250 -0
  108. package/package.json +17 -1
  109. package/dist/replication/trystero/P2PReplicatorBase.d.ts +0 -19
  110. package/dist/replication/trystero/P2PReplicatorCore.d.ts +0 -8
  111. package/dist/replication/trystero/P2PReplicatorCore.js +0 -56
  112. package/dist/replication/trystero/TrysteroReplicatorP2PConnection.d.ts +0 -2
  113. package/dist/replication/trystero/TrysteroReplicatorP2PConnection.js +0 -4
  114. /package/dist/replication/{trystero/P2PReplicatorBase.js → ReplicatorInstance.js} +0 -0
@@ -0,0 +1,61 @@
1
+ import type { LiveSyncReplicatorEnv } from "../LiveSyncAbstractReplicator.js";
2
+ import { P2PRoomSession } from "./P2PRoomSession.js";
3
+ import type { ReplicatorHostEnv } from "./types.js";
4
+ import { type P2PConnectionProbeAdmissionResult, type P2PConnectionProbeSettings } from "./P2PConnectionProbeAdmission.js";
5
+ type P2PRoomSessionFactory = (env: ReplicatorHostEnv) => P2PRoomSession;
6
+ /** Session operations shared by the stable service and its compatibility facade. */
7
+ export interface P2PRoomSessionAccess {
8
+ readonly currentSession: P2PRoomSession | undefined;
9
+ readonly isConnected: boolean;
10
+ cancelActiveTransfers(): void;
11
+ open(): Promise<void>;
12
+ close(): Promise<void>;
13
+ }
14
+ /** Persistent reasons for which the service keeps a P2P room available. */
15
+ export type P2PPersistentRoomDemand = "explicit" | "automatic" | "rebuild-continuation";
16
+ /**
17
+ * Owns the one published P2P room session used by a stable P2P service.
18
+ *
19
+ * Compatibility facades may observe and operate on the published session, but
20
+ * they do not own its construction, replacement, or retirement.
21
+ */
22
+ export declare class P2PRoomSessionOwner implements P2PRoomSessionAccess {
23
+ private readonly env;
24
+ private readonly createSession;
25
+ private current?;
26
+ private lifecycleOperation;
27
+ private readonly persistentDemands;
28
+ private readonly finiteDemands;
29
+ private readonly automationCoordinator;
30
+ private activeBinding?;
31
+ constructor(env: LiveSyncReplicatorEnv, createSession?: P2PRoomSessionFactory);
32
+ get currentSession(): P2PRoomSession | undefined;
33
+ get isConnected(): boolean;
34
+ cancelActiveTransfers(): void;
35
+ /** Retire automatic baseline history owned by the previous app lifecycle. */
36
+ beginAutomationLifecycle(): void;
37
+ open(): Promise<void>;
38
+ /** Reconcile one long-lived reason for keeping the room available. */
39
+ setPersistentDemand(demand: P2PPersistentRoomDemand, active: boolean): Promise<void>;
40
+ /**
41
+ * Keep the room available only for the lifetime of one finite operation.
42
+ *
43
+ * The token is internal to the owner. Releasing it cannot close a room
44
+ * retained by another finite operation or by a persistent policy demand.
45
+ */
46
+ runWithFiniteDemand<T>(task: (session: P2PRoomSession) => T | PromiseLike<T>): Promise<T>;
47
+ /** Arbitrate a complete signalling probe on the room lifecycle queue. */
48
+ runConnectionProbe<T>(trialSettings: P2PConnectionProbeSettings, runOwnedTrial: () => Promise<T>): Promise<P2PConnectionProbeAdmissionResult<T>>;
49
+ private reconcileTransport;
50
+ close(): Promise<void>;
51
+ private hasRoomDemand;
52
+ private enqueueLifecycleOperation;
53
+ private closeTransport;
54
+ private bindingsMatch;
55
+ /** Capture immutable session inputs while keeping policy live. */
56
+ private getEffectiveBinding;
57
+ /** Apply policy which can change without retiring the room session. */
58
+ private reconcileCurrentSessionPolicy;
59
+ private buildSessionEnv;
60
+ }
61
+ export {};
@@ -0,0 +1,249 @@
1
+ import { Logger } from "../../common/logger.js";
2
+ import {
3
+ LOG_LEVEL_NOTICE,
4
+ LOG_LEVEL_VERBOSE,
5
+ SETTING_KEY_P2P_DEVICE_NAME
6
+ } from "../../common/types.js";
7
+ import { P2PRoomSession } from "./P2PRoomSession.js";
8
+ import { P2PAutomationCoordinator } from "./P2PAutomationCoordinator.js";
9
+ import { PEER_REPLICATION_READINESS } from "../ReplicatorProvider.js";
10
+ import { getP2PReplicatorConfigurationIdentity } from "./p2pReplicatorConfigurationIdentity.js";
11
+ import {
12
+ ACTIVE_P2P_RELAY_BINDING_CONFLICT,
13
+ activeP2PRelayBindingCovers
14
+ } from "./P2PConnectionProbeAdmission.js";
15
+ class P2PRoomSessionOwner {
16
+ constructor(env, createSession = (sessionEnv) => new P2PRoomSession(sessionEnv)) {
17
+ this.env = env;
18
+ this.createSession = createSession;
19
+ }
20
+ env;
21
+ createSession;
22
+ current;
23
+ lifecycleOperation = Promise.resolve();
24
+ persistentDemands = /* @__PURE__ */ new Set();
25
+ finiteDemands = /* @__PURE__ */ new Set();
26
+ automationCoordinator = new P2PAutomationCoordinator();
27
+ activeBinding;
28
+ get currentSession() {
29
+ return this.current;
30
+ }
31
+ get isConnected() {
32
+ return this.current?.host.isServing ?? false;
33
+ }
34
+ cancelActiveTransfers() {
35
+ this.current?.cancelActiveTransfers();
36
+ }
37
+ /** Retire automatic baseline history owned by the previous app lifecycle. */
38
+ beginAutomationLifecycle() {
39
+ this.automationCoordinator.beginLifecycle();
40
+ }
41
+ async open() {
42
+ await this.setPersistentDemand("explicit", true);
43
+ }
44
+ /** Reconcile one long-lived reason for keeping the room available. */
45
+ async setPersistentDemand(demand, active) {
46
+ const enabled = this.env.services.setting.currentSettings().P2P_Enabled;
47
+ if (active && enabled) {
48
+ this.persistentDemands.add(demand);
49
+ } else {
50
+ this.persistentDemands.delete(demand);
51
+ }
52
+ if (active && !enabled) {
53
+ Logger(this.env.services.context.translate("P2P.NotEnabled"), LOG_LEVEL_NOTICE);
54
+ }
55
+ await this.reconcileTransport();
56
+ }
57
+ /**
58
+ * Keep the room available only for the lifetime of one finite operation.
59
+ *
60
+ * The token is internal to the owner. Releasing it cannot close a room
61
+ * retained by another finite operation or by a persistent policy demand.
62
+ */
63
+ async runWithFiniteDemand(task) {
64
+ if (!this.env.services.setting.currentSettings().P2P_Enabled) {
65
+ throw new Error("P2P is not enabled.");
66
+ }
67
+ const demand = /* @__PURE__ */ Symbol("p2p-finite-room-demand");
68
+ this.finiteDemands.add(demand);
69
+ try {
70
+ await this.reconcileTransport();
71
+ if (!this.finiteDemands.has(demand)) {
72
+ throw new Error("The P2P room demand was retired before the operation started.");
73
+ }
74
+ const session = this.current;
75
+ if (!session?.host.isServing) {
76
+ throw new Error("The P2P room could not be opened for the finite operation.");
77
+ }
78
+ return await task(session);
79
+ } finally {
80
+ if (this.finiteDemands.delete(demand)) {
81
+ await this.reconcileTransport();
82
+ }
83
+ }
84
+ }
85
+ /** Arbitrate a complete signalling probe on the room lifecycle queue. */
86
+ runConnectionProbe(trialSettings, runOwnedTrial) {
87
+ return this.enqueueLifecycleOperation(async () => {
88
+ const current = this.current;
89
+ const activeBinding = this.activeBinding;
90
+ if (current?.host.isServing && activeBinding) {
91
+ if (activeP2PRelayBindingCovers(activeBinding.settings, trialSettings)) {
92
+ return { status: "observed-active" };
93
+ }
94
+ return {
95
+ status: "blocked",
96
+ reason: ACTIVE_P2P_RELAY_BINDING_CONFLICT
97
+ };
98
+ }
99
+ if (current) {
100
+ await this.closeTransport();
101
+ }
102
+ return {
103
+ status: "trial",
104
+ result: await runOwnedTrial()
105
+ };
106
+ });
107
+ }
108
+ async reconcileTransport() {
109
+ await this.enqueueLifecycleOperation(async () => {
110
+ if (!this.env.services.setting.currentSettings().P2P_Enabled) {
111
+ this.persistentDemands.clear();
112
+ this.finiteDemands.clear();
113
+ }
114
+ if (!this.hasRoomDemand()) {
115
+ await this.closeTransport();
116
+ return;
117
+ }
118
+ const binding = this.getEffectiveBinding();
119
+ if (this.current?.host.isServing && this.bindingsMatch(this.activeBinding, binding)) {
120
+ this.reconcileCurrentSessionPolicy(this.current);
121
+ Logger("P2P replicator is already open.");
122
+ return;
123
+ }
124
+ if (this.current) {
125
+ await this.closeTransport();
126
+ }
127
+ let candidate;
128
+ try {
129
+ candidate = this.createSession(this.buildSessionEnv(binding));
130
+ await candidate.open();
131
+ if (!candidate.host.isServing) {
132
+ throw new Error("The P2P room did not start serving.");
133
+ }
134
+ const currentBinding = this.getEffectiveBinding();
135
+ if (!currentBinding.enabled || !this.hasRoomDemand() || !this.bindingsMatch(binding, currentBinding)) {
136
+ await candidate.retire();
137
+ return;
138
+ }
139
+ this.current = candidate;
140
+ this.activeBinding = binding;
141
+ this.reconcileCurrentSessionPolicy(candidate);
142
+ } catch (error) {
143
+ await candidate?.retire(error).catch((retirementError) => {
144
+ Logger(retirementError, LOG_LEVEL_VERBOSE);
145
+ });
146
+ Logger(error instanceof Error ? error.message : "Error while opening P2P connection", LOG_LEVEL_NOTICE);
147
+ Logger(error, LOG_LEVEL_VERBOSE);
148
+ this.current = void 0;
149
+ this.activeBinding = void 0;
150
+ }
151
+ });
152
+ }
153
+ async close() {
154
+ this.persistentDemands.clear();
155
+ this.finiteDemands.clear();
156
+ await this.enqueueLifecycleOperation(async () => {
157
+ await this.closeTransport();
158
+ });
159
+ }
160
+ hasRoomDemand() {
161
+ return this.persistentDemands.size > 0 || this.finiteDemands.size > 0;
162
+ }
163
+ enqueueLifecycleOperation(operation) {
164
+ const queued = this.lifecycleOperation.catch(() => void 0).then(operation);
165
+ this.lifecycleOperation = queued.then(
166
+ () => void 0,
167
+ () => void 0
168
+ );
169
+ return queued;
170
+ }
171
+ async closeTransport() {
172
+ const session = this.current;
173
+ this.current = void 0;
174
+ this.activeBinding = void 0;
175
+ if (session) {
176
+ await session.retire();
177
+ }
178
+ }
179
+ bindingsMatch(current, candidate) {
180
+ return current?.database === candidate.database && current.signature === candidate.signature;
181
+ }
182
+ /** Capture immutable session inputs while keeping policy live. */
183
+ getEffectiveBinding() {
184
+ const settings = {
185
+ ...this.env.services.setting.currentSettings()
186
+ };
187
+ const deviceName = this.env.services.config.getSmallConfig(SETTING_KEY_P2P_DEVICE_NAME) || this.env.services.vault.getVaultName();
188
+ const database = this.env.services.database.localDatabase.localDatabase;
189
+ this.automationCoordinator.reconcileIdentity(
190
+ JSON.stringify([
191
+ settings.P2P_AppID || "self-hosted-livesync",
192
+ settings.P2P_roomID,
193
+ settings.P2P_passphrase
194
+ ]),
195
+ database
196
+ );
197
+ return {
198
+ database,
199
+ enabled: settings.P2P_Enabled,
200
+ settings,
201
+ deviceName,
202
+ signature: JSON.stringify([getP2PReplicatorConfigurationIdentity(settings), deviceName])
203
+ };
204
+ }
205
+ /** Apply policy which can change without retiring the room session. */
206
+ reconcileCurrentSessionPolicy(session) {
207
+ session.replicator.reconcileAutoBroadcast(this.env.services.setting.currentSettings().P2P_AutoBroadcast);
208
+ }
209
+ buildSessionEnv(binding) {
210
+ const services = this.env.services;
211
+ return {
212
+ events: services.context.events,
213
+ translate: services.context.translate,
214
+ settings: binding.settings,
215
+ currentSettings: () => services.setting.currentSettings(),
216
+ db: binding.database,
217
+ get simpleStore() {
218
+ return services.keyValueDB.openSimpleStore("p2p-sync");
219
+ },
220
+ deviceName: binding.deviceName,
221
+ get platform() {
222
+ return services.API.getPlatform();
223
+ },
224
+ get confirm() {
225
+ return services.API.confirm;
226
+ },
227
+ runFiniteReplicationActivity: (task, options) => services.replicator.runFiniteReplicationActivity(task, options),
228
+ canStartOrdinaryReplication: (showMessage = false) => services.replication.isReplicationReady(showMessage, PEER_REPLICATION_READINESS),
229
+ automationCoordinator: this.automationCoordinator,
230
+ processReplicatedDocs: async (docs) => {
231
+ const currentSettings = services.setting.currentSettings();
232
+ if (currentSettings.suspendParseReplicationResult) {
233
+ const docLength = docs.length;
234
+ if (docLength > 0) {
235
+ Logger(
236
+ `P2P sync, but parseReplicationResult is suspended. Ignoring ${docLength} documents.`,
237
+ LOG_LEVEL_VERBOSE
238
+ );
239
+ }
240
+ return;
241
+ }
242
+ await services.replication.parseSynchroniseResult(docs);
243
+ }
244
+ };
245
+ }
246
+ }
247
+ export {
248
+ P2PRoomSessionOwner
249
+ };
@@ -1,8 +1,11 @@
1
1
  import { type EntryDoc, type ObsidianLiveSyncSettings } from "../../common/types.js";
2
+ import { type LOG_LEVEL } from "octagonal-wheels/common/logger";
2
3
  import { type ProgressInfo } from "../../pouchdb/ReplicatorShim.js";
3
4
  import type { Confirm } from "../../interfaces/Confirm.js";
4
5
  import { type Advertisement, type ReplicatorHostEnv } from "./types.js";
5
6
  import { EVENT_P2P_REPLICATOR_PROGRESS, EVENT_P2P_REPLICATOR_STATUS, P2PHost } from "./TrysteroReplicatorP2PServer.js";
7
+ import type { P2PFiniteOperationOwner } from "./P2PRoomSession.js";
8
+ import { type P2PReplicationWireResult } from "./P2PReplicationWire.js";
6
9
  export type P2PReplicatorStatus = {
7
10
  isBroadcasting: boolean;
8
11
  replicatingTo: string[];
@@ -39,6 +42,58 @@ export type P2PReplicationReport = {
39
42
  isActive: boolean;
40
43
  };
41
44
  });
45
+ /**
46
+ * In-process outcome of one P2P replication request.
47
+ *
48
+ * The failed variant deliberately retains an `Error`-compatible value for
49
+ * local callers. RPC handlers must convert it to `P2PReplicationWireResult`,
50
+ * because native `Error` properties do not survive JSON serialisation.
51
+ */
52
+ export type P2PReplicationResult = {
53
+ readonly status: "completed";
54
+ readonly ok: true;
55
+ readonly error?: never;
56
+ } | {
57
+ readonly status: "cancelled";
58
+ readonly ok?: false;
59
+ readonly error?: never;
60
+ } | {
61
+ readonly status: "failed";
62
+ readonly ok?: false;
63
+ readonly error: unknown;
64
+ };
65
+ export type P2PConfiguredTargetResult = {
66
+ readonly name: string;
67
+ readonly peerId?: string;
68
+ } & ({
69
+ readonly status: "completed";
70
+ } | {
71
+ readonly status: "cancelled";
72
+ } | {
73
+ readonly status: "missing";
74
+ } | {
75
+ readonly status: "rejected";
76
+ } | {
77
+ readonly status: "undecided";
78
+ } | {
79
+ readonly status: "failed";
80
+ readonly error: unknown;
81
+ });
82
+ /** Explicit result of configured, unattended P2P target synchronisation. */
83
+ export type P2PConfiguredReplicationResult = {
84
+ readonly status: "completed";
85
+ readonly targets: readonly P2PConfiguredTargetResult[];
86
+ } | {
87
+ readonly status: "cancelled";
88
+ readonly targets: readonly P2PConfiguredTargetResult[];
89
+ } | {
90
+ readonly status: "blocked";
91
+ readonly reason: "no-targets";
92
+ readonly targets: readonly [];
93
+ } | {
94
+ readonly status: "partial";
95
+ readonly targets: readonly P2PConfiguredTargetResult[];
96
+ };
42
97
  declare global {
43
98
  interface LSEvents {
44
99
  [EVENT_P2P_REPLICATOR_STATUS]: P2PReplicatorStatus;
@@ -55,18 +110,27 @@ export type AllReplicationClientStatus = {
55
110
  };
56
111
  export declare class TrysteroReplicator {
57
112
  _env: ReplicatorHostEnv;
113
+ private readonly finiteOperationOwner?;
114
+ private disposed;
115
+ private readonly fallbackAutomationCoordinator;
58
116
  server?: P2PHost;
59
117
  replicationStatus(): {};
60
118
  get settings(): import("../../common/types.js").P2PSyncSetting;
119
+ /** Latest room-local policy settings supplied by the owning host. */
120
+ get currentSettings(): import("../../common/types.js").P2PSyncSetting;
61
121
  get db(): PouchDB.Database<EntryDoc>;
62
122
  get deviceName(): string;
63
123
  get platform(): string;
64
124
  get confirm(): Confirm;
65
125
  get translate(): import("../../context.js").MessageTranslator;
126
+ private get automationCoordinator();
66
127
  private runFiniteReplicationActivity;
67
128
  private canStartOrdinaryReplication;
68
- constructor(env: ReplicatorHostEnv, server?: P2PHost);
129
+ constructor(env: ReplicatorHostEnv, server?: P2PHost, finiteOperationOwner?: P2PFiniteOperationOwner);
130
+ private runSessionFiniteOperation;
69
131
  close(): Promise<void>;
132
+ /** Close the transport and release resources owned for this object's lifetime. */
133
+ dispose(): Promise<void>;
70
134
  open(): Promise<void>;
71
135
  makeSureOpened(): Promise<void>;
72
136
  get autoSyncPeers(): RegExp[];
@@ -77,31 +141,27 @@ export declare class TrysteroReplicator {
77
141
  setOnSetup(): void;
78
142
  clearOnSetup(): void;
79
143
  getTweakSettings(fromPeerId: string): Promise<Partial<ObsidianLiveSyncSettings>>;
144
+ private handleSynchronisationRequest;
80
145
  getCommands(): {
81
- reqSync: (fromPeerId: string) => Promise<{
82
- error: any;
83
- ok?: undefined;
84
- } | {
85
- ok: boolean;
86
- error?: undefined;
87
- }>;
146
+ reqSync: (fromPeerId: string) => Promise<P2PReplicationWireResult>;
88
147
  "!reqAuth": (fromPeerId: string) => Promise<boolean>;
89
148
  getTweakSettings: (fromPeerId: string) => Promise<Partial<ObsidianLiveSyncSettings>>;
90
149
  onProgress: (fromPeerId: string) => Promise<{
91
- error: Error;
150
+ error: import("../../rpc/index.js").RpcErrorShape;
92
151
  }>;
93
152
  getAllConfig: (fromPeerId: string) => Promise<string | {
94
- error: Error;
153
+ error: import("../../rpc/index.js").RpcErrorShape;
95
154
  }>;
96
155
  onProgressAcknowledged: (fromPeerId: string, info: ProgressInfo) => Promise<void>;
97
156
  getIsBroadcasting: () => Promise<boolean>;
98
157
  requestBroadcasting: (peerId: string) => Promise<true | {
99
- error: Error;
158
+ error: import("../../rpc/index.js").RpcErrorShape;
100
159
  }>;
101
160
  };
102
- requestAuthenticate(peerId: string): Promise<boolean>;
161
+ requestAuthenticate(peerId: string, signal?: AbortSignal): Promise<boolean>;
103
162
  lastSeq: string | number;
104
- requestSynchroniseToPeer(peerId: string): Promise<Awaited<ReturnType<ReturnType<typeof this.getCommands>["reqSync"]>>>;
163
+ requestSynchroniseToPeer(peerId: string, callerSignal?: AbortSignal): Promise<P2PReplicationResult>;
164
+ private requestSynchroniseToPeerWithinSession;
105
165
  requestSynchroniseToAllAvailablePeers(): Promise<void>;
106
166
  dispatchStatus(): void;
107
167
  requestStatus(): void;
@@ -109,44 +169,36 @@ export declare class TrysteroReplicator {
109
169
  _isBroadcasting: boolean;
110
170
  disableBroadcastChanges(): void;
111
171
  enableBroadcastChanges(): void;
172
+ /** Apply automatic broadcast policy without restarting this room. */
173
+ reconcileAutoBroadcast(enabled: boolean): void;
112
174
  get knownAdvertisements(): Advertisement[];
113
175
  availableReplicationPairs: Set<string>;
114
- sync(remotePeer: string, showNotice?: boolean): Promise<{
115
- error: any;
116
- ok?: undefined;
117
- } | {
118
- ok: boolean;
119
- error?: undefined;
120
- }>;
176
+ sync(remotePeer: string, showNotice?: boolean, callerSignal?: AbortSignal): Promise<P2PReplicationResult>;
177
+ private syncWithinSession;
121
178
  _replicateToPeers: Set<string>;
122
179
  _replicateFromPeers: Set<string>;
123
180
  dispatchReplicationProgress(peerId: string, info?: ProgressInfo): void;
124
181
  onReplicationProgress(peerId: string, info?: ProgressInfo): boolean;
125
182
  onProgressAcknowledged(peerId: string, info?: ProgressInfo): boolean;
126
183
  acknowledgeProgress(remotePeerId: string, info?: ProgressInfo): void;
127
- replicateFrom(remotePeer: string, showNotice?: boolean, fromStart?: boolean, skipOrdinaryReplicationPolicy?: boolean): Promise<{
128
- error: any;
129
- ok?: undefined;
130
- } | {
131
- ok: boolean;
132
- error?: undefined;
133
- }>;
184
+ replicateFrom(remotePeer: string, showNotice?: boolean, fromStart?: boolean, skipOrdinaryReplicationPolicy?: boolean, callerSignal?: AbortSignal): Promise<P2PReplicationResult>;
185
+ private replicateFromWithinSession;
134
186
  notifyProgress(excludePeerId?: string): Promise<void>;
135
187
  requestBroadcastChanges(peerId: string): Promise<unknown>;
136
188
  getRemoteIsBroadcasting(peerId: string): Promise<unknown>;
137
189
  _watchingPeers: Set<string>;
138
190
  watchPeer(peerId: string): void;
139
191
  unwatchPeer(peerId: string): void;
140
- onUpdateDatabase(fromPeerId: string): Promise<false | {
141
- error: any;
142
- ok?: undefined;
143
- } | {
144
- ok: boolean;
145
- error?: undefined;
146
- }>;
192
+ onUpdateDatabase(fromPeerId: string): Promise<false | P2PReplicationResult>;
147
193
  getRemoteConfig(peerId: string): Promise<false | ObsidianLiveSyncSettings>;
148
- checkTweakValues(peerId: string): Promise<boolean>;
149
- replicateFromCommand(showResult?: boolean): Promise<void>;
194
+ /** Compare peer settings without exceeding the presentation authority of the initiating call. */
195
+ checkTweakValues(peerId: string, signal?: AbortSignal, logLevel?: LOG_LEVEL): Promise<boolean>;
196
+ private configuredPeerNames;
197
+ private findAdvertisement;
198
+ private waitForConfiguredAdvertisements;
199
+ private configuredTargetResult;
200
+ /** Synchronise configured peer targets without opening peer-selection UI. */
201
+ replicateFromCommand(showResult?: boolean, discoveryTimeoutMs?: number, callerSignal?: AbortSignal): Promise<P2PConfiguredReplicationResult>;
150
202
  disconnectFromServer(): void;
151
203
  pauseServe(): Promise<void>;
152
204
  allowReconnection(): void;