@vrtmrz/livesync-commonlib 0.1.19 → 0.1.21
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.
- package/README.md +5 -1
- package/dist/common/models/setting.p2p.d.ts +2 -0
- package/dist/common/models/setting.p2p.js +5 -0
- package/dist/interfaces/ServiceModule.d.ts +13 -4
- package/dist/managers/ChunkFetcher.js +10 -0
- package/dist/p2p/P2PService.d.ts +123 -0
- package/dist/p2p/P2PService.js +271 -0
- package/dist/p2p/index.d.ts +8 -0
- package/dist/p2p/index.js +8 -0
- package/dist/pouchdb/LiveSyncLocalDB.d.ts +3 -0
- package/dist/pouchdb/LiveSyncLocalDB.js +23 -3
- package/dist/pouchdb/ReplicatorShim.d.ts +43 -4
- package/dist/pouchdb/ReplicatorShim.js +78 -5
- package/dist/replication/CentralCompatibility.d.ts +38 -0
- package/dist/replication/CentralCompatibility.js +39 -0
- package/dist/replication/CentralRemoteAdministration.d.ts +84 -0
- package/dist/replication/CentralRemoteAdministration.js +71 -0
- package/dist/replication/LiveSyncAbstractReplicator.d.ts +19 -6
- package/dist/replication/ProviderCapability.d.ts +32 -0
- package/dist/replication/ProviderCapability.js +27 -0
- package/dist/replication/RemoteResource.d.ts +85 -0
- package/dist/replication/RemoteResource.js +17 -0
- package/dist/replication/ReplicatorInstance.d.ts +23 -0
- package/dist/replication/ReplicatorProvider.d.ts +262 -0
- package/dist/replication/ReplicatorProvider.js +150 -0
- package/dist/replication/couchdb/LiveSyncReplicator.d.ts +54 -8
- package/dist/replication/couchdb/LiveSyncReplicator.js +411 -158
- package/dist/replication/index.d.ts +10 -0
- package/dist/replication/index.js +72 -0
- package/dist/replication/journal/JournalSyncCore.d.ts +2 -0
- package/dist/replication/journal/JournalSyncCore.js +18 -5
- package/dist/replication/journal/LiveSyncJournalReplicator.d.ts +38 -10
- package/dist/replication/journal/LiveSyncJournalReplicator.js +271 -63
- package/dist/replication/journal/LiveSyncJournalReplicatorEnv.d.ts +8 -0
- package/dist/replication/journal/objectstore/JournalStorageAdapter.d.ts +2 -0
- package/dist/replication/journal/objectstore/MinioStorageAdapter.d.ts +2 -0
- package/dist/replication/journal/objectstore/MinioStorageAdapter.js +10 -1
- package/dist/replication/trystero/LiveSyncTrysteroReplicator.d.ts +12 -40
- package/dist/replication/trystero/LiveSyncTrysteroReplicator.js +52 -152
- package/dist/replication/trystero/P2PAutomationCoordinator.d.ts +20 -0
- package/dist/replication/trystero/P2PAutomationCoordinator.js +43 -0
- package/dist/replication/trystero/P2PConnectionProbeAdmission.d.ts +32 -0
- package/dist/replication/trystero/P2PConnectionProbeAdmission.js +10 -0
- package/dist/replication/trystero/P2PReplicationWire.d.ts +31 -0
- package/dist/replication/trystero/P2PReplicationWire.js +50 -0
- package/dist/replication/trystero/P2PRoomSession.d.ts +32 -0
- package/dist/replication/trystero/P2PRoomSession.js +101 -0
- package/dist/replication/trystero/P2PRoomSessionOwner.d.ts +61 -0
- package/dist/replication/trystero/P2PRoomSessionOwner.js +249 -0
- package/dist/replication/trystero/TrysteroReplicator.d.ts +88 -36
- package/dist/replication/trystero/TrysteroReplicator.js +273 -113
- package/dist/replication/trystero/TrysteroReplicatorP2PClient.d.ts +7 -4
- package/dist/replication/trystero/TrysteroReplicatorP2PClient.js +21 -14
- package/dist/replication/trystero/TrysteroReplicatorP2PServer.d.ts +26 -3
- package/dist/replication/trystero/TrysteroReplicatorP2PServer.js +84 -39
- package/dist/replication/trystero/UseP2PReplicatorResult.d.ts +10 -6
- package/dist/replication/trystero/addP2PEventHandlers.d.ts +8 -12
- package/dist/replication/trystero/addP2PEventHandlers.js +19 -19
- package/dist/replication/trystero/p2pReplicatorConfigurationIdentity.d.ts +9 -0
- package/dist/replication/trystero/p2pReplicatorConfigurationIdentity.js +30 -0
- package/dist/replication/trystero/types.d.ts +18 -0
- package/dist/replication/trystero/types.js +5 -1
- package/dist/replication/trystero/useP2PReplicatorCommands.d.ts +3 -3
- package/dist/replication/trystero/useP2PReplicatorCommands.js +6 -8
- package/dist/replication/trystero/useP2PReplicatorFeature.d.ts +16 -7
- package/dist/replication/trystero/useP2PReplicatorFeature.js +73 -55
- package/dist/rpc/RpcRoom.d.ts +15 -1
- package/dist/rpc/RpcRoom.js +176 -41
- package/dist/rpc/RpcSession.d.ts +3 -1
- package/dist/rpc/RpcSession.js +2 -2
- package/dist/rpc/index.d.ts +1 -1
- package/dist/rpc/transports/trysteroUtils.js +2 -1
- package/dist/rpc/types.d.ts +26 -1
- package/dist/serviceFeatures/checkRemoteSize.js +5 -2
- package/dist/serviceModules/Rebuilder.js +66 -56
- package/dist/services/base/AppLifecycleService.d.ts +4 -0
- package/dist/services/base/AppLifecycleService.js +4 -0
- package/dist/services/base/ControlService.js +0 -4
- package/dist/services/base/DatabaseEventService.js +1 -1
- package/dist/services/base/IService.d.ts +105 -8
- package/dist/services/base/ReadinessEvaluator.d.ts +40 -0
- package/dist/services/base/ReadinessEvaluator.js +16 -0
- package/dist/services/base/RemoteConnection.d.ts +3 -0
- package/dist/services/base/RemoteService.js +2 -2
- package/dist/services/base/ReplicationService.d.ts +45 -10
- package/dist/services/base/ReplicationService.js +250 -91
- package/dist/services/base/ReplicationService.readiness.d.ts +52 -0
- package/dist/services/base/ReplicationService.readiness.js +87 -0
- package/dist/services/base/ReplicationService.typedReplication.d.ts +93 -0
- package/dist/services/base/ReplicationService.typedReplication.js +214 -0
- package/dist/services/base/ReplicatorService.activeReplicatorState.d.ts +47 -0
- package/dist/services/base/ReplicatorService.activeReplicatorState.js +107 -0
- package/dist/services/base/ReplicatorService.centralRemoteAdministration.d.ts +5 -0
- package/dist/services/base/ReplicatorService.centralRemoteAdministration.js +44 -0
- package/dist/services/base/ReplicatorService.d.ts +75 -14
- package/dist/services/base/ReplicatorService.js +232 -53
- package/dist/services/base/ReplicatorService.remoteResourceResolver.d.ts +4 -0
- package/dist/services/base/ReplicatorService.remoteResourceResolver.js +11 -0
- package/dist/services/base/TweakValueService.d.ts +3 -2
- package/dist/services/implements/injectable/InjectableTweakValueService.d.ts +1 -1
- package/dist/services/lib/HandlerUtils.d.ts +24 -0
- package/dist/services/lib/HandlerUtils.js +40 -0
- package/docs/development.md +40 -7
- package/docs/p2p-transport-lifecycle.md +135 -11
- package/docs/proven-in-use.md +5 -1
- package/docs/remote-configurations.md +4 -0
- package/docs/service-feature-composition.md +250 -0
- package/package.json +17 -1
- package/dist/replication/trystero/P2PReplicatorBase.d.ts +0 -19
- package/dist/replication/trystero/P2PReplicatorCore.d.ts +0 -8
- package/dist/replication/trystero/P2PReplicatorCore.js +0 -56
- package/dist/replication/trystero/TrysteroReplicatorP2PConnection.d.ts +0 -2
- package/dist/replication/trystero/TrysteroReplicatorP2PConnection.js +0 -4
- /package/dist/replication/{trystero/P2PReplicatorBase.js → ReplicatorInstance.js} +0 -0
|
@@ -10,22 +10,29 @@ class TrysteroReplicatorP2PClient {
|
|
|
10
10
|
get remoteDB() {
|
|
11
11
|
return this._remoteDB;
|
|
12
12
|
}
|
|
13
|
+
/** Bind the reverse database RPC calls to one finite-operation signal. */
|
|
14
|
+
getRemoteDB(signal) {
|
|
15
|
+
return signal ? this._bindRemoteDB(signal) : this._remoteDB;
|
|
16
|
+
}
|
|
13
17
|
constructor(server, connectedPeerId) {
|
|
14
18
|
this._server = server;
|
|
15
19
|
this._connectedPeerId = connectedPeerId;
|
|
16
20
|
this._remoteDB = this._bindRemoteDB();
|
|
17
21
|
}
|
|
18
|
-
_bindRemoteDB() {
|
|
22
|
+
_bindRemoteDB(signal) {
|
|
19
23
|
return {
|
|
20
|
-
info: this.bindRemoteFunction("info"),
|
|
21
|
-
changes: this.bindRemoteFunction("changes"),
|
|
22
|
-
revsDiff: this.bindRemoteFunction("revsDiff"),
|
|
23
|
-
bulkDocs: this.bindRemoteFunction("bulkDocs"),
|
|
24
|
-
bulkGet: this.bindRemoteFunction("bulkGet", BULK_GET_RPC_TIMEOUT),
|
|
25
|
-
put: this.bindRemoteFunction("put"),
|
|
26
|
-
get: this.bindRemoteFunction("get")
|
|
24
|
+
info: this.bindRemoteFunction("info", DEFAULT_RPC_TIMEOUT, signal),
|
|
25
|
+
changes: this.bindRemoteFunction("changes", DEFAULT_RPC_TIMEOUT, signal),
|
|
26
|
+
revsDiff: this.bindRemoteFunction("revsDiff", DEFAULT_RPC_TIMEOUT, signal),
|
|
27
|
+
bulkDocs: this.bindRemoteFunction("bulkDocs", DEFAULT_RPC_TIMEOUT, signal),
|
|
28
|
+
bulkGet: this.bindRemoteFunction("bulkGet", BULK_GET_RPC_TIMEOUT, signal),
|
|
29
|
+
put: this.bindRemoteFunction("put", DEFAULT_RPC_TIMEOUT, signal),
|
|
30
|
+
get: this.bindRemoteFunction("get", DEFAULT_RPC_TIMEOUT, signal)
|
|
27
31
|
};
|
|
28
32
|
}
|
|
33
|
+
getCallOptions(timeout, signal) {
|
|
34
|
+
return { timeoutMs: timeout, signal };
|
|
35
|
+
}
|
|
29
36
|
_sendRPC(type, args, timeout = DEFAULT_RPC_TIMEOUT) {
|
|
30
37
|
const room = this._server?.rpcRoom;
|
|
31
38
|
if (!room) {
|
|
@@ -36,21 +43,21 @@ class TrysteroReplicatorP2PClient {
|
|
|
36
43
|
}
|
|
37
44
|
__onResponse(_data) {
|
|
38
45
|
}
|
|
39
|
-
bindRemoteFunction(type, timeout = DEFAULT_RPC_TIMEOUT) {
|
|
46
|
+
bindRemoteFunction(type, timeout = DEFAULT_RPC_TIMEOUT, signal) {
|
|
40
47
|
return async (...args) => {
|
|
41
48
|
const room = this._server?.rpcRoom;
|
|
42
49
|
if (!room) {
|
|
43
50
|
throw new Error("Not connected to any room");
|
|
44
51
|
}
|
|
45
|
-
return await room.session(this._connectedPeerId).call(toRpcMethodName(type), args, timeout);
|
|
52
|
+
return await room.session(this._connectedPeerId).call(toRpcMethodName(type), args, this.getCallOptions(timeout, signal));
|
|
46
53
|
};
|
|
47
54
|
}
|
|
48
|
-
async invokeRemoteFunction(type, args, timeout = DEFAULT_RPC_TIMEOUT) {
|
|
55
|
+
async invokeRemoteFunction(type, args, timeout = DEFAULT_RPC_TIMEOUT, signal) {
|
|
49
56
|
const room = this._server?.rpcRoom;
|
|
50
57
|
if (!room) {
|
|
51
58
|
throw new Error("Not connected to any room");
|
|
52
59
|
}
|
|
53
|
-
return await room.session(this._connectedPeerId).call(toRpcMethodName(type), args, timeout);
|
|
60
|
+
return await room.session(this._connectedPeerId).call(toRpcMethodName(type), args, this.getCallOptions(timeout, signal));
|
|
54
61
|
}
|
|
55
62
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic function binder, so we can't be more specific about the types here.
|
|
56
63
|
bindRemoteObjectFunctions(key, timeout = DEFAULT_RPC_TIMEOUT) {
|
|
@@ -63,12 +70,12 @@ class TrysteroReplicatorP2PClient {
|
|
|
63
70
|
};
|
|
64
71
|
}
|
|
65
72
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This is a generic function binder, so we can't be more specific about the types here.
|
|
66
|
-
async invokeRemoteObjectFunction(key, args, timeout = DEFAULT_RPC_TIMEOUT) {
|
|
73
|
+
async invokeRemoteObjectFunction(key, args, timeout = DEFAULT_RPC_TIMEOUT, signal) {
|
|
67
74
|
const room = this._server?.rpcRoom;
|
|
68
75
|
if (!room) {
|
|
69
76
|
throw new Error("Not connected to any room");
|
|
70
77
|
}
|
|
71
|
-
return await room.session(this._connectedPeerId).call(toRpcMethodName(key.toString()), args, timeout);
|
|
78
|
+
return await room.session(this._connectedPeerId).call(toRpcMethodName(key.toString()), args, this.getCallOptions(timeout, signal));
|
|
72
79
|
}
|
|
73
80
|
close() {
|
|
74
81
|
this._remoteDB = void 0;
|
|
@@ -4,7 +4,7 @@ import { type ReplicatorHostEnv, type FullFilledDeviceInfo, type Request, type R
|
|
|
4
4
|
import { StoredMapLike } from "../../dataobject/StoredMap.js";
|
|
5
5
|
import { TrysteroReplicatorP2PClient } from "./TrysteroReplicatorP2PClient.js";
|
|
6
6
|
import { Computed } from "octagonal-wheels/dataobject/Computed";
|
|
7
|
-
import { RpcRoom, type JsonLike } from "../../rpc/index.js";
|
|
7
|
+
import { RpcRoom, type JsonLike, type RpcRequestContext } from "../../rpc/index.js";
|
|
8
8
|
import { type DiagRTCStats } from "../../rpc/transports/DiagRTCPeerConnections.types.js";
|
|
9
9
|
export type PeerInfo = Advertisement & {
|
|
10
10
|
isAccepted: boolean | undefined;
|
|
@@ -20,6 +20,8 @@ export type RevokeAcceptanceDecision = {
|
|
|
20
20
|
peerId: string;
|
|
21
21
|
name: string;
|
|
22
22
|
};
|
|
23
|
+
/** Non-interactive result of evaluating the persisted and automatic peer policy. */
|
|
24
|
+
export type P2PPeerAcceptance = "accepted" | "rejected" | "undecided" | "unknown";
|
|
23
25
|
export type P2PServerInfo = {
|
|
24
26
|
isConnected: boolean;
|
|
25
27
|
knownAdvertisements: PeerInfo[];
|
|
@@ -27,6 +29,11 @@ export type P2PServerInfo = {
|
|
|
27
29
|
roomId: string;
|
|
28
30
|
diag: DiagRTCStats;
|
|
29
31
|
};
|
|
32
|
+
/** Peer callbacks bound to one room session rather than the global event hub. */
|
|
33
|
+
export interface P2PSessionPeerHandlers {
|
|
34
|
+
onAdvertisement(peer: Advertisement): void | Promise<void>;
|
|
35
|
+
onPeerLeft(peerId: string): void;
|
|
36
|
+
}
|
|
30
37
|
export declare const EVENT_SERVER_STATUS = "p2p-server-status";
|
|
31
38
|
export declare const EVENT_MAKE_DECISION = "make-decision-p2p-peer";
|
|
32
39
|
export declare const EVENT_REVOKE_DECISION = "revoke-decision-p2p-peer";
|
|
@@ -63,6 +70,9 @@ export declare class TrysteroReplicatorP2PServer {
|
|
|
63
70
|
_rpcRoom?: RpcRoom;
|
|
64
71
|
protected _peerStatusEventCleanup: (() => void) | undefined;
|
|
65
72
|
protected _peerFailureAnalysisCleanup: (() => void) | undefined;
|
|
73
|
+
private _platformUnloadCleanup;
|
|
74
|
+
private _sessionPeerHandlers;
|
|
75
|
+
private _hostLifetimeEnded;
|
|
66
76
|
protected _peerConnectionEventCleanup(): void;
|
|
67
77
|
_diagStats: DiagRTCStats;
|
|
68
78
|
get isDisposed(): boolean;
|
|
@@ -70,8 +80,12 @@ export declare class TrysteroReplicatorP2PServer {
|
|
|
70
80
|
ensureLeaved(): Promise<void>;
|
|
71
81
|
setRoom(room: Room): Promise<void>;
|
|
72
82
|
shutdown(): Promise<void>;
|
|
83
|
+
/** Release subscriptions whose lifetime is the host object rather than one transport join. */
|
|
84
|
+
dispose(): void;
|
|
73
85
|
dispatchConnectionStatus(): Promise<void>;
|
|
74
86
|
constructor(env: ReplicatorHostEnv, _serverPeerId?: string);
|
|
87
|
+
/** Attach callbacks owned by the current room session and return their disposer. */
|
|
88
|
+
setSessionPeerHandlers(handlers: P2PSessionPeerHandlers): () => void;
|
|
75
89
|
makeDecision(decision: AcceptanceDecision): Promise<void>;
|
|
76
90
|
revokeDecision(decision: RevokeAcceptanceDecision): Promise<void>;
|
|
77
91
|
get room(): Room;
|
|
@@ -79,6 +93,8 @@ export declare class TrysteroReplicatorP2PServer {
|
|
|
79
93
|
get db(): PouchDB.Database<import("../../common/types.js").EntryDoc>;
|
|
80
94
|
get confirm(): import("../../interfaces/Confirm.js").Confirm;
|
|
81
95
|
get settings(): P2PSyncSetting;
|
|
96
|
+
/** Latest admission and enablement policy for this room. */
|
|
97
|
+
get currentSettings(): P2PSyncSetting;
|
|
82
98
|
get isEnabled(): boolean;
|
|
83
99
|
get deviceInfo(): FullFilledDeviceInfo;
|
|
84
100
|
_sendAdvertisement?: (data: Advertisement, peerId?: string) => Promise<void>;
|
|
@@ -92,20 +108,27 @@ export declare class TrysteroReplicatorP2PServer {
|
|
|
92
108
|
_confirmUserToAccept(peerId: string): Promise<boolean>;
|
|
93
109
|
_acceptablePeers: Computed<[settings: P2PSyncSetting], RegExp[]>;
|
|
94
110
|
_shouldDenyPeers: Computed<[settings: P2PSyncSetting], RegExp[]>;
|
|
111
|
+
/**
|
|
112
|
+
* Evaluate peer admission without opening a dialogue or changing a stored
|
|
113
|
+
* decision. Unattended automation uses this boundary before starting RPC.
|
|
114
|
+
*/
|
|
115
|
+
evaluatePeerAcceptance(peerId: string): Promise<P2PPeerAcceptance>;
|
|
95
116
|
isAcceptablePeer(peerId: string): Promise<boolean>;
|
|
96
117
|
__send(data: Payload, peerId: string): Promise<void>;
|
|
97
118
|
processArrivedRPC(data: Payload, peerId: string): Promise<void>;
|
|
98
119
|
private _onPeerJoin;
|
|
99
120
|
private _onPeerLeave;
|
|
100
121
|
onAfterJoinRoom(): void;
|
|
101
|
-
startService(bindings?: BindableObject[]): Promise<void>;
|
|
102
|
-
start(bindings?: BindableObject[]): Promise<void>;
|
|
122
|
+
startService(bindings?: BindableObject[], beforeAdvertisement?: () => void): Promise<void>;
|
|
123
|
+
start(bindings?: BindableObject[], beforeAdvertisement?: () => void): Promise<void>;
|
|
103
124
|
/**
|
|
104
125
|
* @deprecated Use serveFunction or serveObject instead. This is only for backward compatibility and may be removed in the future.
|
|
105
126
|
* @param type
|
|
106
127
|
* @param func
|
|
107
128
|
*/
|
|
108
129
|
serveFunction<T extends JsonLike[], U>(type: string, func: (peerId: string, ...args: T) => U | Promise<U>): void;
|
|
130
|
+
/** Serve one function whose finite work can observe caller cancellation. */
|
|
131
|
+
serveCancellationAwareFunction<T extends JsonLike[], U>(type: string, func: (context: RpcRequestContext, peerId: string, ...args: T) => U | Promise<U>): void;
|
|
109
132
|
serveObject<T>(obj: BindableObject<T>): void;
|
|
110
133
|
__onResponse(data: Response, peerId: string): void;
|
|
111
134
|
__onRequest(data: Request, peerId: string): Promise<void>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { selfId, joinRoom } from "@trystero-p2p/nostr";
|
|
2
|
-
import { LOG_LEVEL_INFO, LOG_LEVEL_NOTICE } from "../../common/types.js";
|
|
2
|
+
import { AutoAccepting, LOG_LEVEL_INFO, LOG_LEVEL_NOTICE } from "../../common/types.js";
|
|
3
3
|
import { LOG_LEVEL_VERBOSE, Logger } from "../../common/logger.js";
|
|
4
4
|
import {
|
|
5
5
|
DIRECTION_RESPONSE,
|
|
6
|
+
resolveCurrentP2PSettings,
|
|
6
7
|
ResponsePreventedError,
|
|
7
8
|
DIRECTION_REQUEST
|
|
8
9
|
} from "./types.js";
|
|
@@ -19,6 +20,7 @@ import { toRpcMethodName } from "./rpcCompat.js";
|
|
|
19
20
|
import { generateJoinRoomOptions } from "../../rpc/transports/trysteroUtils.js";
|
|
20
21
|
import { subscribeConnectionStatus, subscribeFailureDiagnosis } from "../../rpc/transports/DiagRTCPeerConnections.js";
|
|
21
22
|
import {} from "../../rpc/transports/DiagRTCPeerConnections.types.js";
|
|
23
|
+
import { asRpcErrorShape } from "../../rpc/errors.js";
|
|
22
24
|
const EVENT_SERVER_STATUS = "p2p-server-status";
|
|
23
25
|
const EVENT_MAKE_DECISION = "make-decision-p2p-peer";
|
|
24
26
|
const EVENT_REVOKE_DECISION = "revoke-decision-p2p-peer";
|
|
@@ -42,6 +44,9 @@ class TrysteroReplicatorP2PServer {
|
|
|
42
44
|
_rpcRoom;
|
|
43
45
|
_peerStatusEventCleanup = void 0;
|
|
44
46
|
_peerFailureAnalysisCleanup = void 0;
|
|
47
|
+
_platformUnloadCleanup;
|
|
48
|
+
_sessionPeerHandlers;
|
|
49
|
+
_hostLifetimeEnded = false;
|
|
45
50
|
_peerConnectionEventCleanup() {
|
|
46
51
|
if (this._peerStatusEventCleanup) {
|
|
47
52
|
this._peerStatusEventCleanup();
|
|
@@ -95,7 +100,15 @@ class TrysteroReplicatorP2PServer {
|
|
|
95
100
|
Logger(ex, LOG_LEVEL_VERBOSE);
|
|
96
101
|
}
|
|
97
102
|
}
|
|
103
|
+
/** Release subscriptions whose lifetime is the host object rather than one transport join. */
|
|
104
|
+
dispose() {
|
|
105
|
+
this._hostLifetimeEnded = true;
|
|
106
|
+
this._platformUnloadCleanup?.();
|
|
107
|
+
this._platformUnloadCleanup = void 0;
|
|
108
|
+
this._sessionPeerHandlers = void 0;
|
|
109
|
+
}
|
|
98
110
|
async dispatchConnectionStatus() {
|
|
111
|
+
if (this._hostLifetimeEnded) return;
|
|
99
112
|
const adsTasks = [...this.knownAdvertisements].map(async (e) => {
|
|
100
113
|
const isAccepted = await this.acceptedPeers.get(e.name);
|
|
101
114
|
const isTemporaryAccepted = this.temporaryAcceptedPeers.get(e.peerId);
|
|
@@ -106,6 +119,7 @@ class TrysteroReplicatorP2PServer {
|
|
|
106
119
|
};
|
|
107
120
|
});
|
|
108
121
|
const ads = await Promise.all(adsTasks);
|
|
122
|
+
if (this._hostLifetimeEnded) return;
|
|
109
123
|
this._env.events.emitEvent(EVENT_SERVER_STATUS, {
|
|
110
124
|
isConnected: this.isServing,
|
|
111
125
|
knownAdvertisements: ads,
|
|
@@ -117,7 +131,7 @@ class TrysteroReplicatorP2PServer {
|
|
|
117
131
|
constructor(env, _serverPeerId = selfId) {
|
|
118
132
|
this._env = env;
|
|
119
133
|
this._serverPeerId = _serverPeerId;
|
|
120
|
-
this._env.events.onEvent(EVENT_PLATFORM_UNLOADED, () => {
|
|
134
|
+
this._platformUnloadCleanup = this._env.events.onEvent(EVENT_PLATFORM_UNLOADED, () => {
|
|
121
135
|
void this.shutdown();
|
|
122
136
|
});
|
|
123
137
|
this.acceptedPeers = new StoredMapLike(
|
|
@@ -125,6 +139,15 @@ class TrysteroReplicatorP2PServer {
|
|
|
125
139
|
"p2p-device-decisions"
|
|
126
140
|
);
|
|
127
141
|
}
|
|
142
|
+
/** Attach callbacks owned by the current room session and return their disposer. */
|
|
143
|
+
setSessionPeerHandlers(handlers) {
|
|
144
|
+
this._sessionPeerHandlers = handlers;
|
|
145
|
+
return () => {
|
|
146
|
+
if (this._sessionPeerHandlers === handlers) {
|
|
147
|
+
this._sessionPeerHandlers = void 0;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
128
151
|
async makeDecision(decision) {
|
|
129
152
|
if (decision.decision) {
|
|
130
153
|
if (decision.isTemporary) {
|
|
@@ -161,8 +184,12 @@ class TrysteroReplicatorP2PServer {
|
|
|
161
184
|
get settings() {
|
|
162
185
|
return this._env.settings;
|
|
163
186
|
}
|
|
187
|
+
/** Latest admission and enablement policy for this room. */
|
|
188
|
+
get currentSettings() {
|
|
189
|
+
return resolveCurrentP2PSettings(this._env);
|
|
190
|
+
}
|
|
164
191
|
get isEnabled() {
|
|
165
|
-
return this.
|
|
192
|
+
return this.currentSettings.P2P_Enabled;
|
|
166
193
|
}
|
|
167
194
|
get deviceInfo() {
|
|
168
195
|
return {
|
|
@@ -173,7 +200,6 @@ class TrysteroReplicatorP2PServer {
|
|
|
173
200
|
};
|
|
174
201
|
}
|
|
175
202
|
_sendAdvertisement;
|
|
176
|
-
// _advertisementTimer?: ReturnType<typeof setInterval>;
|
|
177
203
|
sendAdvertisement(peerId) {
|
|
178
204
|
if (!this.isEnabled) return;
|
|
179
205
|
const devInfo = this.deviceInfo;
|
|
@@ -187,28 +213,12 @@ class TrysteroReplicatorP2PServer {
|
|
|
187
213
|
void this._sendAdvertisement(data, peerId);
|
|
188
214
|
}
|
|
189
215
|
}
|
|
190
|
-
// startAdvertisementBroadcast() {
|
|
191
|
-
// if (this._advertisementTimer) {
|
|
192
|
-
// clearInterval(this._advertisementTimer);
|
|
193
|
-
// }
|
|
194
|
-
// this._advertisementTimer = setInterval(() => {
|
|
195
|
-
// if (!this.isServing || !this.isEnabled) {
|
|
196
|
-
// return;
|
|
197
|
-
// }
|
|
198
|
-
// this.sendAdvertisement();
|
|
199
|
-
// }, ADVERTISEMENT_REBROADCAST_INTERVAL_MS);
|
|
200
|
-
// }
|
|
201
|
-
// stopAdvertisementBroadcast() {
|
|
202
|
-
// if (this._advertisementTimer) {
|
|
203
|
-
// clearInterval(this._advertisementTimer);
|
|
204
|
-
// this._advertisementTimer = undefined;
|
|
205
|
-
// }
|
|
206
|
-
// }
|
|
207
216
|
_knownAdvertisements = /* @__PURE__ */ new Map();
|
|
208
217
|
get knownAdvertisements() {
|
|
209
218
|
return [...this._knownAdvertisements.values()];
|
|
210
219
|
}
|
|
211
220
|
onAdvertisement(data, peerId) {
|
|
221
|
+
if (this._hostLifetimeEnded) return;
|
|
212
222
|
if (!this.isEnabled) return;
|
|
213
223
|
Logger(`Advertisement from ${peerId}`, LOG_LEVEL_VERBOSE);
|
|
214
224
|
if (peerId === this.serverPeerId) return;
|
|
@@ -216,6 +226,7 @@ class TrysteroReplicatorP2PServer {
|
|
|
216
226
|
if (data.peerId !== peerId) return;
|
|
217
227
|
this._knownAdvertisements.set(peerId, data);
|
|
218
228
|
void this.dispatchConnectionStatus();
|
|
229
|
+
void Promise.resolve().then(() => this._sessionPeerHandlers?.onAdvertisement(data)).catch((error) => Logger(error, LOG_LEVEL_VERBOSE));
|
|
219
230
|
void this._env.events.emitEvent(EVENT_ADVERTISEMENT_RECEIVED, data);
|
|
220
231
|
}
|
|
221
232
|
acceptedPeers;
|
|
@@ -278,25 +289,40 @@ You can chose as follows:
|
|
|
278
289
|
return `${settings?.P2P_AutoDenyingPeers ?? ""}`.split(",").map((e) => e.trim()).filter((e) => !!e).map((e) => e.startsWith("~") ? new RegExp(e.substring(1), "i") : new RegExp(`^${e}$`, "i"));
|
|
279
290
|
}
|
|
280
291
|
});
|
|
281
|
-
|
|
282
|
-
|
|
292
|
+
/**
|
|
293
|
+
* Evaluate peer admission without opening a dialogue or changing a stored
|
|
294
|
+
* decision. Unattended automation uses this boundary before starting RPC.
|
|
295
|
+
*/
|
|
296
|
+
async evaluatePeerAcceptance(peerId) {
|
|
297
|
+
if (!this.isEnabled) return "unknown";
|
|
283
298
|
const peerInfo = this._knownAdvertisements.get(peerId);
|
|
284
|
-
if (!peerInfo) return
|
|
299
|
+
if (!peerInfo) return "unknown";
|
|
285
300
|
const peerName = peerInfo.name;
|
|
286
|
-
if (this.temporaryAcceptedPeers.has(peerId))
|
|
301
|
+
if (this.temporaryAcceptedPeers.has(peerId)) {
|
|
302
|
+
return this.temporaryAcceptedPeers.get(peerId) ? "accepted" : "rejected";
|
|
303
|
+
}
|
|
287
304
|
const accepted = await this.acceptedPeers.get(peerName);
|
|
288
|
-
if (accepted !== void 0 && accepted !== null) return accepted;
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
305
|
+
if (accepted !== void 0 && accepted !== null) return accepted ? "accepted" : "rejected";
|
|
306
|
+
const currentSettings = { ...this.currentSettings };
|
|
307
|
+
const isAcceptable = (await this._acceptablePeers.update(currentSettings)).value.some((e) => e.test(peerName));
|
|
308
|
+
const isDeny = (await this._shouldDenyPeers.update(currentSettings)).value.some((e) => e.test(peerName));
|
|
309
|
+
if (isDeny) return "rejected";
|
|
310
|
+
if (isAcceptable || currentSettings.P2P_AutoAccepting === AutoAccepting.ALL) return "accepted";
|
|
311
|
+
return "undecided";
|
|
312
|
+
}
|
|
313
|
+
async isAcceptablePeer(peerId) {
|
|
314
|
+
const acceptance = await this.evaluatePeerAcceptance(peerId);
|
|
315
|
+
if (acceptance === "accepted") {
|
|
316
|
+
const peerName = this._knownAdvertisements.get(peerId)?.name;
|
|
317
|
+
const persisted = peerName ? await this.acceptedPeers.get(peerName) : void 0;
|
|
318
|
+
if (!this.temporaryAcceptedPeers.has(peerId) && persisted == null) {
|
|
319
|
+
this.temporaryAcceptedPeers.set(peerId, true);
|
|
320
|
+
void this.dispatchConnectionStatus();
|
|
321
|
+
}
|
|
295
322
|
return true;
|
|
296
323
|
}
|
|
297
|
-
if (
|
|
298
|
-
|
|
299
|
-
}
|
|
324
|
+
if (acceptance === "rejected" || acceptance === "unknown") return false;
|
|
325
|
+
if (this.currentSettings.P2P_IsHeadless) return false;
|
|
300
326
|
return await this.confirmUserToAccept(peerId);
|
|
301
327
|
}
|
|
302
328
|
async __send(data, peerId) {
|
|
@@ -330,6 +356,7 @@ You can chose as follows:
|
|
|
330
356
|
}
|
|
331
357
|
}
|
|
332
358
|
_onPeerJoin(peerId) {
|
|
359
|
+
if (this._hostLifetimeEnded) return;
|
|
333
360
|
if (!this._room) {
|
|
334
361
|
Logger(`Received peer join event from ${peerId}, but no active room. Ignoring.`, LOG_LEVEL_VERBOSE);
|
|
335
362
|
return;
|
|
@@ -338,8 +365,10 @@ You can chose as follows:
|
|
|
338
365
|
this.sendAdvertisement(peerId);
|
|
339
366
|
}
|
|
340
367
|
_onPeerLeave(peerId) {
|
|
368
|
+
if (this._hostLifetimeEnded) return;
|
|
341
369
|
Logger(`Peer left: ${peerId}`, LOG_LEVEL_VERBOSE);
|
|
342
370
|
this._knownAdvertisements.delete(peerId);
|
|
371
|
+
void Promise.resolve().then(() => this._sessionPeerHandlers?.onPeerLeft(peerId)).catch((error) => Logger(error, LOG_LEVEL_VERBOSE));
|
|
343
372
|
void this._env.events.emitEvent(EVENT_DEVICE_LEAVED, peerId);
|
|
344
373
|
void this.dispatchConnectionStatus();
|
|
345
374
|
}
|
|
@@ -397,7 +426,7 @@ You can chose as follows:
|
|
|
397
426
|
this._env.events.emitEvent(EVENT_P2P_CONNECTED);
|
|
398
427
|
void this.dispatchConnectionStatus();
|
|
399
428
|
}
|
|
400
|
-
async startService(bindings = []) {
|
|
429
|
+
async startService(bindings = [], beforeAdvertisement) {
|
|
401
430
|
if (!this.isEnabled) {
|
|
402
431
|
Logger(this._env.translate("P2P.NotEnabled"), LOG_LEVEL_NOTICE);
|
|
403
432
|
return;
|
|
@@ -407,9 +436,10 @@ You can chose as follows:
|
|
|
407
436
|
this._bindingObjects.forEach((b) => {
|
|
408
437
|
this.serveObject(b);
|
|
409
438
|
});
|
|
439
|
+
beforeAdvertisement?.();
|
|
410
440
|
await Promise.resolve(this.sendAdvertisement());
|
|
411
441
|
}
|
|
412
|
-
async start(bindings = []) {
|
|
442
|
+
async start(bindings = [], beforeAdvertisement) {
|
|
413
443
|
await this.shutdown();
|
|
414
444
|
if (!this.settings.P2P_Enabled) {
|
|
415
445
|
Logger(this._env.translate("P2P.NotEnabled"), LOG_LEVEL_NOTICE);
|
|
@@ -436,7 +466,7 @@ You can chose as follows:
|
|
|
436
466
|
this._activeRoomId = roomId;
|
|
437
467
|
this.onAfterJoinRoom();
|
|
438
468
|
void this.dispatchConnectionStatus();
|
|
439
|
-
await this.startService(bindings);
|
|
469
|
+
await this.startService(bindings, beforeAdvertisement);
|
|
440
470
|
}
|
|
441
471
|
/**
|
|
442
472
|
* @deprecated Use serveFunction or serveObject instead. This is only for backward compatibility and may be removed in the future.
|
|
@@ -449,6 +479,13 @@ You can chose as follows:
|
|
|
449
479
|
return await Promise.resolve(func.apply(this, [peerId, ...args]));
|
|
450
480
|
});
|
|
451
481
|
}
|
|
482
|
+
/** Serve one function whose finite work can observe caller cancellation. */
|
|
483
|
+
serveCancellationAwareFunction(type, func) {
|
|
484
|
+
this._rpcRoom?.registerCancellable(
|
|
485
|
+
toRpcMethodName(type),
|
|
486
|
+
async (context, peerId, ...args) => await Promise.resolve(func(context, peerId, ...args))
|
|
487
|
+
);
|
|
488
|
+
}
|
|
452
489
|
serveObject(obj) {
|
|
453
490
|
const keys = Object.keys(obj);
|
|
454
491
|
keys.forEach((key) => {
|
|
@@ -483,7 +520,15 @@ You can chose as follows:
|
|
|
483
520
|
Logger(`Serving function: [FAILED] ${data.type} sending back the failure information`, LOG_LEVEL_VERBOSE);
|
|
484
521
|
Logger(e instanceof Error ? e.message : e, LOG_LEVEL_VERBOSE);
|
|
485
522
|
await this.__send(
|
|
486
|
-
{
|
|
523
|
+
{
|
|
524
|
+
type: data.type,
|
|
525
|
+
seq: data.seq,
|
|
526
|
+
direction: DIRECTION_RESPONSE,
|
|
527
|
+
data: void 0,
|
|
528
|
+
// This deprecated path predates RpcRoom, but it has the same
|
|
529
|
+
// JSON boundary and therefore must not send a native Error.
|
|
530
|
+
error: asRpcErrorShape(e)
|
|
531
|
+
},
|
|
487
532
|
peerId
|
|
488
533
|
);
|
|
489
534
|
}
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import type { ReactiveSource } from "octagonal-wheels/dataobject/reactive_v2";
|
|
2
2
|
import type { LiveSyncTrysteroReplicator } from "./LiveSyncTrysteroReplicator.js";
|
|
3
3
|
import type { P2PLogCollector } from "./P2PLogCollector.js";
|
|
4
|
-
|
|
4
|
+
import type { P2PServiceViews } from "../../p2p/P2PService.js";
|
|
5
|
+
export type UseP2PReplicatorResult = P2PServiceViews & {
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
+
* Compatibility facade retained while existing panes migrate to the
|
|
8
|
+
* focused service views.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
10
|
+
* This facade is stable for the service lifetime, but it is not the active
|
|
11
|
+
* provider adapter. New consumers must request only the service view which
|
|
12
|
+
* they need.
|
|
13
|
+
*
|
|
14
|
+
* @deprecated Use the focused P2P service views instead.
|
|
11
15
|
*/
|
|
12
16
|
readonly replicator: LiveSyncTrysteroReplicator;
|
|
13
17
|
};
|
|
14
18
|
export type P2PPaneParams = {
|
|
15
|
-
/**
|
|
19
|
+
/** @deprecated Migrate panes to the focused P2P service views. */
|
|
16
20
|
readonly replicator: LiveSyncTrysteroReplicator;
|
|
17
21
|
p2pLogCollector: P2PLogCollector;
|
|
18
22
|
storeP2PStatusLine: ReactiveSource<string>;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { LiveSyncEventHub } from "../../hub/hub.js";
|
|
2
2
|
import type { LiveSyncTrysteroReplicator } from "./LiveSyncTrysteroReplicator.js";
|
|
3
3
|
import type { Advertisement } from "./types.js";
|
|
4
|
+
import type { P2PServiceLifecycle } from "../../p2p/P2PService.js";
|
|
4
5
|
/**
|
|
5
6
|
* Minimal interface that a P2P replicator instance should satisfy for addP2PEventHandlers to work.
|
|
6
7
|
*/
|
|
7
8
|
export interface P2PReplicatorLike {
|
|
9
|
+
/** True when peer callbacks are already fenced by the active room session. */
|
|
10
|
+
readonly handlesPeerEventsWithinSession?: boolean;
|
|
8
11
|
onNewPeer(peer: Advertisement): Promise<void> | void;
|
|
9
12
|
onPeerLeaved(peerId: string): void;
|
|
10
13
|
requestStatus(): void;
|
|
@@ -17,21 +20,14 @@ export interface P2PReplicatorLike {
|
|
|
17
20
|
isServing?: boolean;
|
|
18
21
|
};
|
|
19
22
|
}
|
|
23
|
+
/** Host lifecycle subset consumed by the legacy event bridge. */
|
|
24
|
+
export type P2PServiceEventTarget = Pick<P2PServiceLifecycle, "requestStatus" | "openAfterDatabaseRebuild" | "closeForLifecycle" | "reconcileAutoStart">;
|
|
20
25
|
/** Resolves the replicator which currently owns P2P state. */
|
|
21
|
-
export type
|
|
26
|
+
export type P2PEventTarget = P2PReplicatorLike | P2PServiceEventTarget;
|
|
27
|
+
export type P2PReplicatorProvider = () => P2PEventTarget;
|
|
22
28
|
/**
|
|
23
29
|
* Add event handlers for P2P replication related events.
|
|
24
30
|
* @param source A fixed compatibility instance or a provider for a replaceable replicator.
|
|
25
31
|
*/
|
|
26
|
-
export declare function addP2PEventHandlers(source:
|
|
27
|
-
/**
|
|
28
|
-
* open P2P replicator if not opened yet.
|
|
29
|
-
* @param instance
|
|
30
|
-
*/
|
|
31
|
-
export declare function openP2PReplicator(instance: P2PReplicatorLike): Promise<void>;
|
|
32
|
-
/**
|
|
33
|
-
* close P2P replicator
|
|
34
|
-
* @param instance
|
|
35
|
-
*/
|
|
36
|
-
export declare function closeP2PReplicator(instance: P2PReplicatorLike): Promise<void>;
|
|
32
|
+
export declare function addP2PEventHandlers(source: P2PEventTarget | P2PReplicatorProvider, events: LiveSyncEventHub): void;
|
|
37
33
|
export type { LiveSyncTrysteroReplicator };
|
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
import { EVENT_DATABASE_REBUILT, EVENT_PLATFORM_UNLOADED, EVENT_SETTING_SAVED } from "../../events/coreEvents.js";
|
|
2
2
|
import { EVENT_ADVERTISEMENT_RECEIVED, EVENT_DEVICE_LEAVED, EVENT_REQUEST_STATUS } from "./TrysteroReplicatorP2PServer.js";
|
|
3
|
+
function isServiceEventTarget(target) {
|
|
4
|
+
return "reconcileAutoStart" in target;
|
|
5
|
+
}
|
|
3
6
|
function addP2PEventHandlers(source, events) {
|
|
4
7
|
const current = () => typeof source === "function" ? source() : source;
|
|
5
8
|
events.onEvent(EVENT_ADVERTISEMENT_RECEIVED, (peer) => {
|
|
6
|
-
|
|
9
|
+
const target = current();
|
|
10
|
+
if ("onNewPeer" in target && target.handlesPeerEventsWithinSession !== true) void target.onNewPeer(peer);
|
|
7
11
|
});
|
|
8
12
|
events.onEvent(EVENT_DEVICE_LEAVED, (peerId) => {
|
|
9
|
-
current()
|
|
13
|
+
const target = current();
|
|
14
|
+
if ("onPeerLeaved" in target && target.handlesPeerEventsWithinSession !== true) target.onPeerLeaved(peerId);
|
|
10
15
|
});
|
|
11
16
|
events.onEvent(EVENT_REQUEST_STATUS, () => {
|
|
12
17
|
current().requestStatus();
|
|
13
18
|
});
|
|
14
19
|
events.onEvent(EVENT_DATABASE_REBUILT, async () => {
|
|
15
|
-
|
|
20
|
+
const target = current();
|
|
21
|
+
await (isServiceEventTarget(target) ? target.openAfterDatabaseRebuild() : target.open());
|
|
16
22
|
});
|
|
17
23
|
events.onEvent(EVENT_PLATFORM_UNLOADED, () => {
|
|
18
|
-
|
|
24
|
+
const target = current();
|
|
25
|
+
void (isServiceEventTarget(target) ? target.closeForLifecycle() : target.close());
|
|
19
26
|
});
|
|
20
27
|
events.onEvent(EVENT_SETTING_SAVED, async (settings) => {
|
|
21
|
-
const
|
|
28
|
+
const target = current();
|
|
29
|
+
if (isServiceEventTarget(target)) {
|
|
30
|
+
await target.reconcileAutoStart(settings);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
22
33
|
if (settings.P2P_Enabled && settings.P2P_AutoStart) {
|
|
23
|
-
await
|
|
34
|
+
await target.open();
|
|
24
35
|
return;
|
|
25
36
|
}
|
|
26
|
-
await
|
|
37
|
+
await target.close();
|
|
27
38
|
});
|
|
28
39
|
}
|
|
29
|
-
async function openP2PReplicator(instance) {
|
|
30
|
-
const isOpen = instance.isServing ?? instance.server?.isServing ?? false;
|
|
31
|
-
if (!isOpen) {
|
|
32
|
-
await instance.open();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
async function closeP2PReplicator(instance) {
|
|
36
|
-
await instance.close();
|
|
37
|
-
}
|
|
38
40
|
export {
|
|
39
|
-
addP2PEventHandlers
|
|
40
|
-
closeP2PReplicator,
|
|
41
|
-
openP2PReplicator
|
|
41
|
+
addP2PEventHandlers
|
|
42
42
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RemoteDBSettings } from "../../common/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Project only values which fix the effective P2P transport generation.
|
|
4
|
+
*
|
|
5
|
+
* Persisted profile identifiers, enablement, and room automation or admission
|
|
6
|
+
* policy are deliberately excluded. The returned value can contain
|
|
7
|
+
* credentials and must not be logged, persisted, or displayed.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getP2PReplicatorConfigurationIdentity(settings: RemoteDBSettings): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { P2PConnectionPaths } from "../../common/models/setting.const.js";
|
|
2
|
+
import {
|
|
3
|
+
hasValidP2PTurnServerUrl,
|
|
4
|
+
normaliseP2PConnectionPath,
|
|
5
|
+
normaliseP2PMaxWirePayloadBytes,
|
|
6
|
+
splitP2PRelayUrls,
|
|
7
|
+
splitP2PTurnServerUrls
|
|
8
|
+
} from "../../common/models/setting.p2p.js";
|
|
9
|
+
function getP2PReplicatorConfigurationIdentity(settings) {
|
|
10
|
+
const turnServerValue = settings.P2P_turnServers ?? "";
|
|
11
|
+
const turnServers = splitP2PTurnServerUrls(turnServerValue);
|
|
12
|
+
const configuredPath = normaliseP2PConnectionPath(settings.P2P_connectionPath);
|
|
13
|
+
const effectivePath = configuredPath === P2PConnectionPaths.Relay && hasValidP2PTurnServerUrl(turnServerValue) ? P2PConnectionPaths.Relay : P2PConnectionPaths.Automatic;
|
|
14
|
+
const turnAuthentication = turnServers.length > 0 ? [settings.P2P_turnUsername, settings.P2P_turnCredential] : void 0;
|
|
15
|
+
return JSON.stringify([
|
|
16
|
+
"p2p",
|
|
17
|
+
settings.P2P_AppID || "self-hosted-livesync",
|
|
18
|
+
settings.P2P_roomID,
|
|
19
|
+
settings.P2P_passphrase,
|
|
20
|
+
splitP2PRelayUrls(settings.P2P_relays),
|
|
21
|
+
turnServers,
|
|
22
|
+
turnAuthentication,
|
|
23
|
+
normaliseP2PMaxWirePayloadBytes(settings.P2P_maxWirePayloadBytes),
|
|
24
|
+
effectivePath,
|
|
25
|
+
settings.P2P_useDiagRTC ?? false
|
|
26
|
+
]);
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
getP2PReplicatorConfigurationIdentity
|
|
30
|
+
};
|
|
@@ -5,6 +5,7 @@ import type { Confirm } from "../../interfaces/Confirm.js";
|
|
|
5
5
|
import type { AsyncActivityRunner } from "../../interfaces/AsyncActivityRunner.js";
|
|
6
6
|
import type { LiveSyncEventHub } from "../../hub/hub.js";
|
|
7
7
|
import type { MessageTranslator } from "../../services/base/MessageTranslator.js";
|
|
8
|
+
import type { P2PAutomationCoordinator } from "./P2PAutomationCoordinator.js";
|
|
8
9
|
export declare const DIRECTION_REQUEST = "request";
|
|
9
10
|
export type DIRECTION_REQUEST = typeof DIRECTION_REQUEST;
|
|
10
11
|
export declare const DIRECTION_RESPONSE = "response";
|
|
@@ -81,14 +82,31 @@ export interface ReplicatorHostEnv extends ReplicatorHost {
|
|
|
81
82
|
events: LiveSyncEventHub;
|
|
82
83
|
/** Message translation owned by the containing Commonlib service composition. */
|
|
83
84
|
translate: MessageTranslator;
|
|
85
|
+
/**
|
|
86
|
+
* Immutable settings snapshot captured for this room session.
|
|
87
|
+
*
|
|
88
|
+
* Room join options, RPC framing, and other session-owned resources must
|
|
89
|
+
* use this snapshot so one session cannot mix transport generations.
|
|
90
|
+
*/
|
|
84
91
|
settings: P2PSyncSetting;
|
|
92
|
+
/**
|
|
93
|
+
* Return the latest host settings for policy evaluated on an open room.
|
|
94
|
+
*
|
|
95
|
+
* Older direct consumers may omit this port; they retain snapshot
|
|
96
|
+
* behaviour through the `settings` fallback.
|
|
97
|
+
*/
|
|
98
|
+
currentSettings?(): P2PSyncSetting;
|
|
85
99
|
db: PouchDB.Database<EntryDoc>;
|
|
86
100
|
simpleStore: SimpleStore<unknown>;
|
|
87
101
|
runFiniteReplicationActivity?: AsyncActivityRunner["run"];
|
|
88
102
|
/** Lightweight, repeatable host policy checked before ordinary P2P replication starts. */
|
|
89
103
|
canStartOrdinaryReplication?(showMessage?: boolean): Promise<boolean>;
|
|
104
|
+
/** Stable automatic-transfer state supplied by the owning P2P service. */
|
|
105
|
+
automationCoordinator?: P2PAutomationCoordinator;
|
|
90
106
|
processReplicatedDocs(docs: Array<PouchDB.Core.ExistingDocument<EntryDoc>>): void | Promise<void>;
|
|
91
107
|
}
|
|
108
|
+
/** Resolve policy settings without weakening the immutable room snapshot. */
|
|
109
|
+
export declare function resolveCurrentP2PSettings(env: ReplicatorHostEnv): P2PSyncSetting;
|
|
92
110
|
export type Advertisement = {
|
|
93
111
|
peerId: string;
|
|
94
112
|
name: string;
|