@fairfox/polly 0.51.0 → 0.53.0
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/dist/src/mesh.js +121 -7
- package/dist/src/mesh.js.map +4 -4
- package/dist/src/polly-ui/markdown.js +2 -3
- package/dist/src/polly-ui/markdown.js.map +2 -2
- package/dist/src/shared/lib/mesh-client.d.ts +29 -0
- package/dist/src/shared/lib/mesh-webrtc-adapter.d.ts +127 -6
- package/dist/tools/test/src/visual/index.js +37 -11
- package/dist/tools/test/src/visual/index.js.map +4 -4
- package/package.json +1 -1
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
* signalling client.
|
|
46
46
|
*/
|
|
47
47
|
import { type Message, NetworkAdapter, type PeerId, type PeerMetadata } from "@automerge/automerge-repo/slim";
|
|
48
|
+
import type { MeshKeyring } from "./mesh-network-adapter";
|
|
48
49
|
import type { MeshSignalingClient } from "./mesh-signaling-client";
|
|
49
50
|
/** Standard STUN servers for NAT traversal. In production, callers who
|
|
50
51
|
* need TURN fallback for peers behind symmetric NATs should replace this
|
|
@@ -64,8 +65,41 @@ export interface MeshWebRTCAdapterOptions {
|
|
|
64
65
|
* one by sending an SDP offer through the signalling channel. Peers
|
|
65
66
|
* not in this list can still connect by sending an offer *to* this
|
|
66
67
|
* adapter. The natural source for this list is the keyring's
|
|
67
|
-
* knownPeers map keys.
|
|
68
|
+
* knownPeers map keys.
|
|
69
|
+
*
|
|
70
|
+
* Used only when {@link keyringSource} is not supplied. With
|
|
71
|
+
* `keyringSource` set the adapter reads `knownPeers` live from the
|
|
72
|
+
* keyring on every initiation decision, which is the shape
|
|
73
|
+
* {@link createMeshClient} wires up so post-construction
|
|
74
|
+
* {@link applyPairingToken} calls take effect without the consumer
|
|
75
|
+
* having to call {@link MeshWebRTCAdapter.addKnownPeer} by hand. */
|
|
68
76
|
knownPeerIds?: string[];
|
|
77
|
+
/** Live keyring source. When supplied, the adapter reads
|
|
78
|
+
* `knownPeers` from `keyringSource()` on every initiation decision
|
|
79
|
+
* instead of a Set captured at construction. Combined with the
|
|
80
|
+
* periodic re-sweep started in {@link MeshWebRTCAdapter.connect},
|
|
81
|
+
* this makes mutations to `keyring.knownPeers` — including the ones
|
|
82
|
+
* produced by {@link applyPairingToken} after the mesh client is up
|
|
83
|
+
* — visible to the dial path within at most one sweep interval. The
|
|
84
|
+
* crypto layer already re-reads the keyring on every send and
|
|
85
|
+
* receive; this option closes the same loop for the WebRTC adapter.
|
|
86
|
+
*
|
|
87
|
+
* Polly issue #103: without this, a long-lived daemon that pairs a
|
|
88
|
+
* new device after its mesh client is constructed never dials the
|
|
89
|
+
* new peer — the adapter's captured Set stays stale even though the
|
|
90
|
+
* keyring contains the new entry, and the lex-tie-break rule in
|
|
91
|
+
* {@link MeshWebRTCAdapter.shouldInitiateTo} can leave both peers
|
|
92
|
+
* waiting for the other to offer indefinitely. */
|
|
93
|
+
keyringSource?: () => MeshKeyring;
|
|
94
|
+
/** How often the adapter re-evaluates whether to dial peers in the
|
|
95
|
+
* signalling roster. The sweep is what catches peers that became
|
|
96
|
+
* authorised in the keyring after their `peer-joined` notification
|
|
97
|
+
* already fired — the adapter has no other event to hang the retry
|
|
98
|
+
* on, so it polls. Cheap: one Map lookup per present peer, fired at
|
|
99
|
+
* most once per interval. Defaults to 2000ms; tests override to
|
|
100
|
+
* shorten the failure budget. Set to 0 to disable the sweep
|
|
101
|
+
* (the captured-set behaviour, kept only for migration). */
|
|
102
|
+
knownPeersRefreshIntervalMs?: number;
|
|
69
103
|
/** Optional ICE server list override. Defaults to {@link DEFAULT_ICE_SERVERS}. */
|
|
70
104
|
iceServers?: RTCIceServer[];
|
|
71
105
|
/** Optional data channel label. Defaults to "polly-mesh". Applications
|
|
@@ -90,8 +124,24 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
90
124
|
/** Peers this adapter is willing to dial. Mutable so callers that pair
|
|
91
125
|
* a new device after construction (e.g. a CLI `add-device` process whose
|
|
92
126
|
* mesh client is long-lived across the pair ceremony) can register the
|
|
93
|
-
* new peer with {@link addKnownPeer} without restarting the client.
|
|
127
|
+
* new peer with {@link addKnownPeer} without restarting the client.
|
|
128
|
+
*
|
|
129
|
+
* Used only in the captured-set fallback path — when no
|
|
130
|
+
* {@link keyringSource} is supplied. With `keyringSource` set, the
|
|
131
|
+
* authoritative source is the live keyring and this Set is unused. */
|
|
94
132
|
private readonly knownPeers;
|
|
133
|
+
/** Live keyring source, or undefined when the adapter is operating in
|
|
134
|
+
* the captured-set fallback shape. See the JSDoc on
|
|
135
|
+
* {@link MeshWebRTCAdapterOptions.keyringSource}. */
|
|
136
|
+
private readonly keyringSource;
|
|
137
|
+
/** Interval handle for the periodic re-sweep that catches peers
|
|
138
|
+
* already in the signalling roster when the keyring grew. Cleared in
|
|
139
|
+
* {@link MeshWebRTCAdapter.disconnect}. */
|
|
140
|
+
private knownPeersRefreshTimer;
|
|
141
|
+
/** Sweep interval. Resolved from
|
|
142
|
+
* {@link MeshWebRTCAdapterOptions.knownPeersRefreshIntervalMs} at
|
|
143
|
+
* construction. Defaults to 2000ms; tests override to 100–250ms. */
|
|
144
|
+
private readonly knownPeersRefreshIntervalMs;
|
|
95
145
|
/** Peers currently visible in the signalling roster — populated by
|
|
96
146
|
* {@link handlePeersPresent} / {@link handlePeerJoined} and pruned by
|
|
97
147
|
* {@link handlePeerLeft}. Read by {@link addKnownPeer} to decide
|
|
@@ -109,10 +159,18 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
109
159
|
private ready;
|
|
110
160
|
private readyResolver;
|
|
111
161
|
/** The peers this adapter will dial. Backward-compatible read accessor
|
|
112
|
-
* for callers that previously iterated the `knownPeerIds` array
|
|
113
|
-
*
|
|
114
|
-
*
|
|
162
|
+
* for callers that previously iterated the `knownPeerIds` array. With
|
|
163
|
+
* a {@link MeshWebRTCAdapterOptions.keyringSource} configured, the
|
|
164
|
+
* value is read live from the keyring; otherwise it falls back to the
|
|
165
|
+
* captured Set populated through the constructor and
|
|
166
|
+
* {@link addKnownPeer}. */
|
|
115
167
|
get knownPeerIds(): string[];
|
|
168
|
+
/** True iff `remotePeerId` is currently in the authoritative
|
|
169
|
+
* knownPeers source — the live keyring when one was supplied, or
|
|
170
|
+
* the captured Set otherwise. Centralises the membership check so
|
|
171
|
+
* {@link shouldInitiateTo} and the JSDoc on
|
|
172
|
+
* {@link MeshWebRTCAdapterOptions.keyringSource} agree on the rule. */
|
|
173
|
+
private hasKnownPeer;
|
|
116
174
|
/** Callback for incoming blob messages. Set by the blob store.
|
|
117
175
|
* Called with the sender's peer ID, the raw header object, and the
|
|
118
176
|
* binary payload (chunk data). */
|
|
@@ -124,6 +182,43 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
124
182
|
* RTCPeerConnection and data channel. Exposed for tests that assert
|
|
125
183
|
* "exactly one channel per pair" after discovery settles. */
|
|
126
184
|
peerSlotCount(): number;
|
|
185
|
+
/** Snapshot of the adapter's per-peer state at the moment of the
|
|
186
|
+
* call. Returned values are plain data — strings and booleans only —
|
|
187
|
+
* so consumers can log, assert on, or render them without retaining
|
|
188
|
+
* references into the adapter's internals.
|
|
189
|
+
*
|
|
190
|
+
* Polly issue #103 asked for an inspection surface so a consumer
|
|
191
|
+
* harness can answer "is the mesh layer in a known good state" from
|
|
192
|
+
* outside polly. This method is that surface. The fields mirror the
|
|
193
|
+
* three layers of the WebRTC connection lifecycle so a "stuck"
|
|
194
|
+
* connection can be diagnosed without reaching for the browser
|
|
195
|
+
* devtools: the SDP signalling state, the ICE checking state, and
|
|
196
|
+
* the unified RTCPeerConnection connection state. A `dataChannel`
|
|
197
|
+
* field reports whether the data channel — the thing the mesh
|
|
198
|
+
* actually carries bytes over — is open.
|
|
199
|
+
*
|
|
200
|
+
* Peers visible in the signalling roster but not yet dialled appear
|
|
201
|
+
* with `slot: undefined`, so a consumer can tell "we know about this
|
|
202
|
+
* peer in signalling but the WebRTC adapter has not started an
|
|
203
|
+
* offer yet" from "we have a slot in some negotiation state". */
|
|
204
|
+
getPeerStateSnapshot(): {
|
|
205
|
+
localPeerId: string;
|
|
206
|
+
knownPeerIds: string[];
|
|
207
|
+
presentPeerIds: string[];
|
|
208
|
+
peers: Array<{
|
|
209
|
+
peerId: string;
|
|
210
|
+
knownInKeyring: boolean;
|
|
211
|
+
presentInSignalling: boolean;
|
|
212
|
+
slot: undefined | {
|
|
213
|
+
signalingState: string;
|
|
214
|
+
iceConnectionState: string;
|
|
215
|
+
connectionState: string;
|
|
216
|
+
dataChannelState: string;
|
|
217
|
+
pendingSendCount: number;
|
|
218
|
+
pendingRemoteIceCount: number;
|
|
219
|
+
};
|
|
220
|
+
}>;
|
|
221
|
+
};
|
|
127
222
|
/** Handle the signalling server's `peer-joined` notification: a new
|
|
128
223
|
* peer has appeared on the relay. If the peer is in `knownPeerIds`
|
|
129
224
|
* and we do not already have a slot for it, and the tie-break rule
|
|
@@ -152,8 +247,22 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
152
247
|
* new entry. Calling this method propagates that into the adapter's
|
|
153
248
|
* own allowlist; if the peer is already in the signalling roster and
|
|
154
249
|
* the tie-break rule names us as the initiator, an SDP offer fires
|
|
155
|
-
* immediately. No-op if the peer is already known.
|
|
250
|
+
* immediately. No-op if the peer is already known.
|
|
251
|
+
*
|
|
252
|
+
* When a {@link MeshWebRTCAdapterOptions.keyringSource} is configured
|
|
253
|
+
* the adapter already reads `knownPeers` live and the periodic sweep
|
|
254
|
+
* picks up the new entry within
|
|
255
|
+
* {@link MeshWebRTCAdapterOptions.knownPeersRefreshIntervalMs} on its
|
|
256
|
+
* own, so explicit calls to this method are not required for
|
|
257
|
+
* correctness — but remain supported for callers that want the
|
|
258
|
+
* "dial now if present" prompt without waiting for the next sweep. */
|
|
156
259
|
addKnownPeer(remotePeerId: string): void;
|
|
260
|
+
/** Re-evaluate every peer currently in the signalling roster and
|
|
261
|
+
* dial the ones the keyring authorises that we do not already have
|
|
262
|
+
* a slot for. The periodic sweep started in {@link connect} calls
|
|
263
|
+
* this; consumers can call it manually to skip the wait after they
|
|
264
|
+
* apply a fresh pairing token. Idempotent. */
|
|
265
|
+
refreshKnownPeers(): void;
|
|
157
266
|
private shouldInitiateTo;
|
|
158
267
|
whenReady(): Promise<void>;
|
|
159
268
|
/**
|
|
@@ -170,6 +279,13 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
170
279
|
*/
|
|
171
280
|
connect(peerId: PeerId, peerMetadata?: PeerMetadata): void;
|
|
172
281
|
disconnect(): void;
|
|
282
|
+
/** Start the periodic re-sweep that catches peers added to the
|
|
283
|
+
* keyring after their `peer-joined` notification has already fired.
|
|
284
|
+
* No-op when no keyringSource was supplied — the captured-set
|
|
285
|
+
* fallback has no live source to re-read, so the sweep would be
|
|
286
|
+
* useless. No-op when the interval is configured to 0. */
|
|
287
|
+
private startKnownPeersSweep;
|
|
288
|
+
private stopKnownPeersSweep;
|
|
173
289
|
/**
|
|
174
290
|
* Send a sync message to a specific remote peer. If no RTCPeerConnection
|
|
175
291
|
* exists yet, the adapter initiates one by producing an SDP offer and
|
|
@@ -199,6 +315,11 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
199
315
|
private handleOffer;
|
|
200
316
|
private handleAnswer;
|
|
201
317
|
private handleIceCandidate;
|
|
318
|
+
/** Drain the per-slot queue of remote ICE candidates that arrived
|
|
319
|
+
* before `setRemoteDescription` completed. Errors per candidate are
|
|
320
|
+
* swallowed for the same reason {@link handleIceCandidate} swallows
|
|
321
|
+
* them — a single bad candidate must not stall the connection. */
|
|
322
|
+
private flushPendingRemoteIce;
|
|
202
323
|
private wireConnection;
|
|
203
324
|
private wireDataChannel;
|
|
204
325
|
private dispatchMessage;
|
|
@@ -6135,12 +6135,23 @@ __export(exports_assert, {
|
|
|
6135
6135
|
CallTracker: () => CallTracker,
|
|
6136
6136
|
AssertionError: () => AssertionError
|
|
6137
6137
|
});
|
|
6138
|
-
|
|
6138
|
+
function __accessProp2(key) {
|
|
6139
|
+
return this[key];
|
|
6140
|
+
}
|
|
6141
|
+
var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __toESMCache_node2, __toESMCache_esm2, __toESM2 = (mod, isNodeMode, target) => {
|
|
6142
|
+
var canCache = mod != null && typeof mod === "object";
|
|
6143
|
+
if (canCache) {
|
|
6144
|
+
var cache = isNodeMode ? __toESMCache_node2 ??= new WeakMap : __toESMCache_esm2 ??= new WeakMap, cached = cache.get(mod);
|
|
6145
|
+
if (cached)
|
|
6146
|
+
return cached;
|
|
6147
|
+
}
|
|
6139
6148
|
target = mod != null ? __create2(__getProtoOf2(mod)) : {};
|
|
6140
6149
|
let to = isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target;
|
|
6141
6150
|
for (let key of __getOwnPropNames2(mod))
|
|
6142
6151
|
if (!__hasOwnProp2.call(to, key))
|
|
6143
|
-
__defProp2(to, key, { get: (
|
|
6152
|
+
__defProp2(to, key, { get: __accessProp2.bind(mod, key), enumerable: true });
|
|
6153
|
+
if (canCache)
|
|
6154
|
+
cache.set(mod, to);
|
|
6144
6155
|
return to;
|
|
6145
6156
|
}, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), require_shams, require_shams2, require_es_object_atoms, require_es_errors, require_eval, require_range, require_ref, require_syntax, require_type, require_uri, require_abs, require_floor, require_max, require_min, require_pow, require_round, require_isNaN, require_sign, require_gOPD, require_gopd, require_es_define_property, require_has_symbols, require_Reflect_getPrototypeOf, require_Object_getPrototypeOf, require_implementation, require_function_bind, require_functionCall, require_functionApply, require_reflectApply, require_actualApply, require_call_bind_apply_helpers, require_get, require_get_proto, require_hasown, require_get_intrinsic, require_call_bound, require_is_arguments, require_is_regex, require_safe_regex_test, require_generator_function, require_is_generator_function, require_is_callable, require_for_each, require_possible_typed_array_names, require_available_typed_arrays, require_define_data_property, require_has_property_descriptors, require_set_function_length, require_applyBind, require_call_bind, require_which_typed_array, require_is_typed_array, require_types, require_isBuffer, require_inherits_browser, require_inherits, require_util, require_errors, require_assertion_error, require_isArguments, require_implementation2, require_object_keys, require_implementation3, require_polyfill, require_implementation4, require_polyfill2, require_callBound, require_define_properties, require_shim, require_object_is, require_implementation5, require_polyfill3, require_shim2, require_is_nan, require_comparisons, require_assert, assert, AssertionError, CallTracker, deepEqual, deepStrictEqual, doesNotMatch, doesNotReject, doesNotThrow, equal, fail, ifError, match, notDeepEqual, notDeepStrictEqual, notEqual, notStrictEqual, ok, rejects, strict, strictEqual, throws, assert_default;
|
|
6146
6157
|
var init_assert = __esm(() => {
|
|
@@ -9108,26 +9119,41 @@ var exports_zlib = {};
|
|
|
9108
9119
|
__export(exports_zlib, {
|
|
9109
9120
|
default: () => export_default
|
|
9110
9121
|
});
|
|
9122
|
+
function __accessProp3(key) {
|
|
9123
|
+
return this[key];
|
|
9124
|
+
}
|
|
9125
|
+
function __exportSetter2(name, newValue) {
|
|
9126
|
+
this[name] = __returnValue2.bind(null, newValue);
|
|
9127
|
+
}
|
|
9111
9128
|
var __create3, __getProtoOf3, __defProp3, __getOwnPropNames3, __hasOwnProp3, __reExport = (target, mod, secondTarget) => {
|
|
9112
|
-
|
|
9129
|
+
var keys = __getOwnPropNames3(mod);
|
|
9130
|
+
for (let key of keys)
|
|
9113
9131
|
if (!__hasOwnProp3.call(target, key) && key !== "default")
|
|
9114
|
-
__defProp3(target, key, { get: (
|
|
9132
|
+
__defProp3(target, key, { get: __accessProp3.bind(mod, key), enumerable: true });
|
|
9115
9133
|
if (secondTarget) {
|
|
9116
|
-
for (let key of
|
|
9134
|
+
for (let key of keys)
|
|
9117
9135
|
if (!__hasOwnProp3.call(secondTarget, key) && key !== "default")
|
|
9118
|
-
__defProp3(secondTarget, key, { get: (
|
|
9136
|
+
__defProp3(secondTarget, key, { get: __accessProp3.bind(mod, key), enumerable: true });
|
|
9119
9137
|
return secondTarget;
|
|
9120
9138
|
}
|
|
9121
|
-
}, __toESM3 = (mod, isNodeMode, target) => {
|
|
9139
|
+
}, __toESMCache_node3, __toESMCache_esm3, __toESM3 = (mod, isNodeMode, target) => {
|
|
9140
|
+
var canCache = mod != null && typeof mod === "object";
|
|
9141
|
+
if (canCache) {
|
|
9142
|
+
var cache = isNodeMode ? __toESMCache_node3 ??= new WeakMap : __toESMCache_esm3 ??= new WeakMap, cached = cache.get(mod);
|
|
9143
|
+
if (cached)
|
|
9144
|
+
return cached;
|
|
9145
|
+
}
|
|
9122
9146
|
target = mod != null ? __create3(__getProtoOf3(mod)) : {};
|
|
9123
9147
|
let to = isNodeMode || !mod || !mod.__esModule ? __defProp3(target, "default", { value: mod, enumerable: true }) : target;
|
|
9124
9148
|
for (let key of __getOwnPropNames3(mod))
|
|
9125
9149
|
if (!__hasOwnProp3.call(to, key))
|
|
9126
|
-
__defProp3(to, key, { get: (
|
|
9150
|
+
__defProp3(to, key, { get: __accessProp3.bind(mod, key), enumerable: true });
|
|
9151
|
+
if (canCache)
|
|
9152
|
+
cache.set(mod, to);
|
|
9127
9153
|
return to;
|
|
9128
|
-
}, __commonJS3 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __export2 = (target, all) => {
|
|
9154
|
+
}, __commonJS3 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __returnValue2 = (v) => v, __export2 = (target, all) => {
|
|
9129
9155
|
for (var name in all)
|
|
9130
|
-
__defProp3(target, name, { get: all[name], enumerable: true, configurable: true, set: (
|
|
9156
|
+
__defProp3(target, name, { get: all[name], enumerable: true, configurable: true, set: __exportSetter2.bind(all, name) });
|
|
9131
9157
|
}, require_zstream, require_common, require_trees, require_adler32, require_crc32, require_messages, require_deflate, require_inffast, require_inftrees, require_inflate, require_constants, require_binding, require_lib, exports_zlib2, import_browserify_zlib, export_default;
|
|
9132
9158
|
var init_zlib = __esm(() => {
|
|
9133
9159
|
__create3 = Object.create;
|
|
@@ -13991,4 +14017,4 @@ export {
|
|
|
13991
14017
|
assertSafeUpdateMode
|
|
13992
14018
|
};
|
|
13993
14019
|
|
|
13994
|
-
//# debugId=
|
|
14020
|
+
//# debugId=51DC7226BD2C4BE464756E2164756E21
|