@fairfox/polly 0.52.0 → 0.54.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 +217 -13
- package/dist/src/mesh.js.map +5 -5
- 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 +43 -0
- package/dist/src/shared/lib/mesh-webrtc-adapter.d.ts +248 -7
- package/dist/src/shared/lib/sync-fragment.d.ts +16 -5
- 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
|
|
@@ -77,6 +111,78 @@ export interface MeshWebRTCAdapterOptions {
|
|
|
77
111
|
* (e.g. `werift` or `@roamhq/wrtc`) when running outside a browser, or
|
|
78
112
|
* to use a custom subclass for tests or instrumentation. */
|
|
79
113
|
RTCPeerConnection?: typeof RTCPeerConnection;
|
|
114
|
+
/** When `true` (the default), the adapter yields to the event loop
|
|
115
|
+
* between the points where a large initial sync would otherwise hold
|
|
116
|
+
* the main thread for tens of seconds: between each batch of
|
|
117
|
+
* fragmented `RTCDataChannel.send` calls on the sender side, and at
|
|
118
|
+
* the boundary between reassembling a sync message and dispatching
|
|
119
|
+
* it (deserialise → MeshNetworkAdapter unwrap → Automerge
|
|
120
|
+
* `applyChanges`) on the receiver side. Set to `false` to recover
|
|
121
|
+
* the pre-#104 tight-loop behaviour; this is the configuration the
|
|
122
|
+
* `POLLY_104_DISABLE_FIX=1` falsification path in
|
|
123
|
+
* `examples/mesh-large-initial-sync` uses to demonstrate the bug
|
|
124
|
+
* against post-fix polly. Production callers should leave this at
|
|
125
|
+
* the default. */
|
|
126
|
+
syncYieldEnabled?: boolean;
|
|
127
|
+
/** Override the sync fragment chunk size. Defaults to
|
|
128
|
+
* {@link SYNC_FRAGMENT_CHUNK_SIZE} (60 KiB), which leaves header
|
|
129
|
+
* overhead inside werift's hard 64 KiB max-message-size cap.
|
|
130
|
+
* Setting this to 64 KiB recreates the pre-#104 fragmentation bug,
|
|
131
|
+
* where peer A's outbound fragments overshoot the cap and werift
|
|
132
|
+
* rejects them silently — sync stalls forever. Used by the
|
|
133
|
+
* `POLLY_104_DISABLE_FIX=1` falsification path. Production callers
|
|
134
|
+
* should leave this at the default. */
|
|
135
|
+
syncFragmentChunkSizeOverride?: number;
|
|
136
|
+
}
|
|
137
|
+
/** Payload of the polly-specific `"sync-progress"` event emitted by
|
|
138
|
+
* {@link MeshWebRTCAdapter}. Consumers can subscribe via the adapter's
|
|
139
|
+
* standard `.on()` surface (the same one that carries `peer-candidate`
|
|
140
|
+
* and `peer-disconnected`) to observe fragment receive and dispatch
|
|
141
|
+
* activity in real time, without polling
|
|
142
|
+
* {@link MeshWebRTCAdapter.getPeerStateSnapshot}. Polly issue #104
|
|
143
|
+
* item 7. */
|
|
144
|
+
export interface SyncProgressEvent {
|
|
145
|
+
/** Remote peer the fragment or dispatch is for. */
|
|
146
|
+
peerId: string;
|
|
147
|
+
/** Lifecycle stage. `fragment-received` fires for each chunk that
|
|
148
|
+
* arrives during reassembly; `dispatch-applied` fires once the
|
|
149
|
+
* reassembled message has been emitted upward to Automerge. */
|
|
150
|
+
kind: "fragment-received" | "dispatch-applied";
|
|
151
|
+
/** Bytes carried by the chunk that triggered the event. Zero for
|
|
152
|
+
* `dispatch-applied`. */
|
|
153
|
+
bytesDelta: number;
|
|
154
|
+
/** Running total of fragments received for the current reassembly. */
|
|
155
|
+
chunksReceived: number;
|
|
156
|
+
/** Running total of bytes received for the current reassembly. */
|
|
157
|
+
bytesReceived: number;
|
|
158
|
+
/** Number of reassembled messages whose dispatch has been scheduled
|
|
159
|
+
* but not yet emitted upward to Automerge. */
|
|
160
|
+
applyBacklog: number;
|
|
161
|
+
/** `performance.now()` at event emission. */
|
|
162
|
+
at: number;
|
|
163
|
+
}
|
|
164
|
+
/** Per-peer view of an in-flight initial sync. Populated by
|
|
165
|
+
* {@link MeshWebRTCAdapter.handleSyncFragment} as fragments of a
|
|
166
|
+
* single reassembly arrive, and reset to `undefined` once the
|
|
167
|
+
* reassembled message has been dispatched. Exposed verbatim through
|
|
168
|
+
* {@link MeshWebRTCAdapter.getPeerStateSnapshot} so a consumer
|
|
169
|
+
* harness can observe progress mid-stream. Polly issue #104 item 7. */
|
|
170
|
+
export interface InFlightSyncSnapshot {
|
|
171
|
+
/** Fragments received for the current reassembly. Cleared once
|
|
172
|
+
* reassembly completes. */
|
|
173
|
+
chunksReceived: number;
|
|
174
|
+
/** Bytes received across the fragments of the current reassembly.
|
|
175
|
+
* The reassembled message will be slightly smaller than this sum
|
|
176
|
+
* because each fragment carries a small header. */
|
|
177
|
+
bytesReceived: number;
|
|
178
|
+
/** `performance.now()` value at the last fragment arrival. */
|
|
179
|
+
lastChunkAt: number;
|
|
180
|
+
/** Count of reassembled messages whose dispatch has been
|
|
181
|
+
* scheduled but not yet run. With the receiver-side `setTimeout(0)`
|
|
182
|
+
* yield enabled, this is normally 0 or 1; with the yield
|
|
183
|
+
* disabled (the falsification path) dispatch runs synchronously
|
|
184
|
+
* and this stays 0. */
|
|
185
|
+
applyBacklog: number;
|
|
80
186
|
}
|
|
81
187
|
/**
|
|
82
188
|
* Automerge-Repo NetworkAdapter backed by real WebRTC data channels.
|
|
@@ -90,8 +196,35 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
90
196
|
/** Peers this adapter is willing to dial. Mutable so callers that pair
|
|
91
197
|
* a new device after construction (e.g. a CLI `add-device` process whose
|
|
92
198
|
* mesh client is long-lived across the pair ceremony) can register the
|
|
93
|
-
* new peer with {@link addKnownPeer} without restarting the client.
|
|
199
|
+
* new peer with {@link addKnownPeer} without restarting the client.
|
|
200
|
+
*
|
|
201
|
+
* Used only in the captured-set fallback path — when no
|
|
202
|
+
* {@link keyringSource} is supplied. With `keyringSource` set, the
|
|
203
|
+
* authoritative source is the live keyring and this Set is unused. */
|
|
94
204
|
private readonly knownPeers;
|
|
205
|
+
/** Live keyring source, or undefined when the adapter is operating in
|
|
206
|
+
* the captured-set fallback shape. See the JSDoc on
|
|
207
|
+
* {@link MeshWebRTCAdapterOptions.keyringSource}. */
|
|
208
|
+
private readonly keyringSource;
|
|
209
|
+
/** Interval handle for the periodic re-sweep that catches peers
|
|
210
|
+
* already in the signalling roster when the keyring grew. Cleared in
|
|
211
|
+
* {@link MeshWebRTCAdapter.disconnect}. */
|
|
212
|
+
private knownPeersRefreshTimer;
|
|
213
|
+
/** Sweep interval. Resolved from
|
|
214
|
+
* {@link MeshWebRTCAdapterOptions.knownPeersRefreshIntervalMs} at
|
|
215
|
+
* construction. Defaults to 2000ms; tests override to 100–250ms. */
|
|
216
|
+
private readonly knownPeersRefreshIntervalMs;
|
|
217
|
+
/** When `true`, the sender side awaits between batches of fragment
|
|
218
|
+
* sends and the receiver side schedules dispatch via `setTimeout(0)`
|
|
219
|
+
* so the JS event loop can drain timers (including the consumer's
|
|
220
|
+
* own setInterval-based liveness probes) between large-message
|
|
221
|
+
* apply calls. Defaults to `true`; set to `false` only by the
|
|
222
|
+
* `POLLY_104_DISABLE_FIX` falsification path. */
|
|
223
|
+
private readonly syncYieldEnabled;
|
|
224
|
+
/** Resolved chunk size for fragmenting oversized messages.
|
|
225
|
+
* Defaults to {@link SYNC_FRAGMENT_CHUNK_SIZE}; can be overridden
|
|
226
|
+
* via {@link MeshWebRTCAdapterOptions.syncFragmentChunkSizeOverride}. */
|
|
227
|
+
private readonly syncFragmentChunkSize;
|
|
95
228
|
/** Peers currently visible in the signalling roster — populated by
|
|
96
229
|
* {@link handlePeersPresent} / {@link handlePeerJoined} and pruned by
|
|
97
230
|
* {@link handlePeerLeft}. Read by {@link addKnownPeer} to decide
|
|
@@ -109,10 +242,18 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
109
242
|
private ready;
|
|
110
243
|
private readyResolver;
|
|
111
244
|
/** The peers this adapter will dial. Backward-compatible read accessor
|
|
112
|
-
* for callers that previously iterated the `knownPeerIds` array
|
|
113
|
-
*
|
|
114
|
-
*
|
|
245
|
+
* for callers that previously iterated the `knownPeerIds` array. With
|
|
246
|
+
* a {@link MeshWebRTCAdapterOptions.keyringSource} configured, the
|
|
247
|
+
* value is read live from the keyring; otherwise it falls back to the
|
|
248
|
+
* captured Set populated through the constructor and
|
|
249
|
+
* {@link addKnownPeer}. */
|
|
115
250
|
get knownPeerIds(): string[];
|
|
251
|
+
/** True iff `remotePeerId` is currently in the authoritative
|
|
252
|
+
* knownPeers source — the live keyring when one was supplied, or
|
|
253
|
+
* the captured Set otherwise. Centralises the membership check so
|
|
254
|
+
* {@link shouldInitiateTo} and the JSDoc on
|
|
255
|
+
* {@link MeshWebRTCAdapterOptions.keyringSource} agree on the rule. */
|
|
256
|
+
private hasKnownPeer;
|
|
116
257
|
/** Callback for incoming blob messages. Set by the blob store.
|
|
117
258
|
* Called with the sender's peer ID, the raw header object, and the
|
|
118
259
|
* binary payload (chunk data). */
|
|
@@ -124,6 +265,44 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
124
265
|
* RTCPeerConnection and data channel. Exposed for tests that assert
|
|
125
266
|
* "exactly one channel per pair" after discovery settles. */
|
|
126
267
|
peerSlotCount(): number;
|
|
268
|
+
/** Snapshot of the adapter's per-peer state at the moment of the
|
|
269
|
+
* call. Returned values are plain data — strings and booleans only —
|
|
270
|
+
* so consumers can log, assert on, or render them without retaining
|
|
271
|
+
* references into the adapter's internals.
|
|
272
|
+
*
|
|
273
|
+
* Polly issue #103 asked for an inspection surface so a consumer
|
|
274
|
+
* harness can answer "is the mesh layer in a known good state" from
|
|
275
|
+
* outside polly. This method is that surface. The fields mirror the
|
|
276
|
+
* three layers of the WebRTC connection lifecycle so a "stuck"
|
|
277
|
+
* connection can be diagnosed without reaching for the browser
|
|
278
|
+
* devtools: the SDP signalling state, the ICE checking state, and
|
|
279
|
+
* the unified RTCPeerConnection connection state. A `dataChannel`
|
|
280
|
+
* field reports whether the data channel — the thing the mesh
|
|
281
|
+
* actually carries bytes over — is open.
|
|
282
|
+
*
|
|
283
|
+
* Peers visible in the signalling roster but not yet dialled appear
|
|
284
|
+
* with `slot: undefined`, so a consumer can tell "we know about this
|
|
285
|
+
* peer in signalling but the WebRTC adapter has not started an
|
|
286
|
+
* offer yet" from "we have a slot in some negotiation state". */
|
|
287
|
+
getPeerStateSnapshot(): {
|
|
288
|
+
localPeerId: string;
|
|
289
|
+
knownPeerIds: string[];
|
|
290
|
+
presentPeerIds: string[];
|
|
291
|
+
peers: Array<{
|
|
292
|
+
peerId: string;
|
|
293
|
+
knownInKeyring: boolean;
|
|
294
|
+
presentInSignalling: boolean;
|
|
295
|
+
slot: undefined | {
|
|
296
|
+
signalingState: string;
|
|
297
|
+
iceConnectionState: string;
|
|
298
|
+
connectionState: string;
|
|
299
|
+
dataChannelState: string;
|
|
300
|
+
pendingSendCount: number;
|
|
301
|
+
pendingRemoteIceCount: number;
|
|
302
|
+
inFlightSync: InFlightSyncSnapshot | undefined;
|
|
303
|
+
};
|
|
304
|
+
}>;
|
|
305
|
+
};
|
|
127
306
|
/** Handle the signalling server's `peer-joined` notification: a new
|
|
128
307
|
* peer has appeared on the relay. If the peer is in `knownPeerIds`
|
|
129
308
|
* and we do not already have a slot for it, and the tie-break rule
|
|
@@ -152,8 +331,22 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
152
331
|
* new entry. Calling this method propagates that into the adapter's
|
|
153
332
|
* own allowlist; if the peer is already in the signalling roster and
|
|
154
333
|
* the tie-break rule names us as the initiator, an SDP offer fires
|
|
155
|
-
* immediately. No-op if the peer is already known.
|
|
334
|
+
* immediately. No-op if the peer is already known.
|
|
335
|
+
*
|
|
336
|
+
* When a {@link MeshWebRTCAdapterOptions.keyringSource} is configured
|
|
337
|
+
* the adapter already reads `knownPeers` live and the periodic sweep
|
|
338
|
+
* picks up the new entry within
|
|
339
|
+
* {@link MeshWebRTCAdapterOptions.knownPeersRefreshIntervalMs} on its
|
|
340
|
+
* own, so explicit calls to this method are not required for
|
|
341
|
+
* correctness — but remain supported for callers that want the
|
|
342
|
+
* "dial now if present" prompt without waiting for the next sweep. */
|
|
156
343
|
addKnownPeer(remotePeerId: string): void;
|
|
344
|
+
/** Re-evaluate every peer currently in the signalling roster and
|
|
345
|
+
* dial the ones the keyring authorises that we do not already have
|
|
346
|
+
* a slot for. The periodic sweep started in {@link connect} calls
|
|
347
|
+
* this; consumers can call it manually to skip the wait after they
|
|
348
|
+
* apply a fresh pairing token. Idempotent. */
|
|
349
|
+
refreshKnownPeers(): void;
|
|
157
350
|
private shouldInitiateTo;
|
|
158
351
|
whenReady(): Promise<void>;
|
|
159
352
|
/**
|
|
@@ -170,6 +363,13 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
170
363
|
*/
|
|
171
364
|
connect(peerId: PeerId, peerMetadata?: PeerMetadata): void;
|
|
172
365
|
disconnect(): void;
|
|
366
|
+
/** Start the periodic re-sweep that catches peers added to the
|
|
367
|
+
* keyring after their `peer-joined` notification has already fired.
|
|
368
|
+
* No-op when no keyringSource was supplied — the captured-set
|
|
369
|
+
* fallback has no live source to re-read, so the sweep would be
|
|
370
|
+
* useless. No-op when the interval is configured to 0. */
|
|
371
|
+
private startKnownPeersSweep;
|
|
372
|
+
private stopKnownPeersSweep;
|
|
173
373
|
/**
|
|
174
374
|
* Send a sync message to a specific remote peer. If no RTCPeerConnection
|
|
175
375
|
* exists yet, the adapter initiates one by producing an SDP offer and
|
|
@@ -177,13 +377,30 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
177
377
|
* queued until the data channel is open.
|
|
178
378
|
*/
|
|
179
379
|
send(message: Message): void;
|
|
380
|
+
/** Number of consecutive fragment sends after which the sender
|
|
381
|
+
* yields to the macrotask queue when {@link syncYieldEnabled} is on.
|
|
382
|
+
* 8 × 64 KiB = 512 KiB of bytes between yields — small enough that
|
|
383
|
+
* a 5 MB sync produces many yield points (and the JS event loop
|
|
384
|
+
* drains the consumer's `setInterval` liveness probes between
|
|
385
|
+
* them), large enough that the per-yield overhead does not dominate
|
|
386
|
+
* the wire cost. */
|
|
387
|
+
private static readonly SEND_YIELD_EVERY_N_FRAGMENTS;
|
|
180
388
|
/** Send raw wire bytes, fragmenting if they exceed the SCTP maxMessageSize
|
|
181
389
|
* cap. The default RTCDataChannel limit is 256 KiB in current Chrome and
|
|
182
390
|
* werift; oversized sends either throw, drop silently, or stall the
|
|
183
391
|
* channel, none of which surface as an error to the caller. Fragments
|
|
184
392
|
* use the same length-prefixed JSON header wire format as ordinary
|
|
185
393
|
* messages but carry a `sync-fragment` type that the receive path
|
|
186
|
-
* detects and reassembles before deserialising.
|
|
394
|
+
* detects and reassembles before deserialising.
|
|
395
|
+
*
|
|
396
|
+
* When {@link MeshWebRTCAdapterOptions.syncYieldEnabled} is true (the
|
|
397
|
+
* default), the loop awaits the macrotask queue every
|
|
398
|
+
* {@link SEND_YIELD_EVERY_N_FRAGMENTS} fragments so the JS event
|
|
399
|
+
* loop drains between batches — without this, a 5–8 MB initial
|
|
400
|
+
* sync produces 78–125 back-to-back `RTCDataChannel.send` calls in
|
|
401
|
+
* a tight loop, starving anything else on the main thread (polly
|
|
402
|
+
* issue #104, sender side). When the option is false the legacy
|
|
403
|
+
* tight-loop shape is preserved for the falsification path. */
|
|
187
404
|
private sendBytesMaybeFragmented;
|
|
188
405
|
/**
|
|
189
406
|
* Entry point the signalling client calls when it receives a signal
|
|
@@ -207,7 +424,31 @@ export declare class MeshWebRTCAdapter extends NetworkAdapter {
|
|
|
207
424
|
private wireConnection;
|
|
208
425
|
private wireDataChannel;
|
|
209
426
|
private dispatchMessage;
|
|
427
|
+
/** Hand a deserialised Automerge message off to whoever is listening
|
|
428
|
+
* on this adapter's `"message"` event. When
|
|
429
|
+
* {@link MeshWebRTCAdapterOptions.syncYieldEnabled} is true (the
|
|
430
|
+
* default), the emit runs on a fresh macrotask so the crypto-unwrap
|
|
431
|
+
* and Automerge `applyChanges` chain downstream of this method does
|
|
432
|
+
* not sit on the same JS stack frame as the wire `onmessage` callback
|
|
433
|
+
* — that's the receiver-side starvation site polly issue #104
|
|
434
|
+
* documents. When the option is false the emit is synchronous,
|
|
435
|
+
* recovering the pre-fix shape used by the falsification path.
|
|
436
|
+
*
|
|
437
|
+
* The `viaFragmentPath` argument tags whether this dispatch came out
|
|
438
|
+
* of a reassembled fragment chain; only those carry an
|
|
439
|
+
* `inFlightSync` reassembly state worth bookkeeping. Small
|
|
440
|
+
* single-message dispatches yield but don't touch inFlightSync. */
|
|
441
|
+
private scheduleEmitMessage;
|
|
442
|
+
private finishInFlightSyncApply;
|
|
443
|
+
private emitSyncProgress;
|
|
210
444
|
private handleSyncFragment;
|
|
445
|
+
/** Dispatch a reassembled fragment payload back through
|
|
446
|
+
* {@link dispatchMessage}, but tagged so the
|
|
447
|
+
* {@link scheduleEmitMessage} path knows it owes a
|
|
448
|
+
* `finishInFlightSyncApply` afterwards. Synchronous re-entry into
|
|
449
|
+
* `dispatchMessage` would lose that signal, so the post-fragment
|
|
450
|
+
* deserialise+emit is inlined here. */
|
|
451
|
+
private dispatchReassembled;
|
|
211
452
|
/** Peer IDs with an open data channel, suitable for blob requests. */
|
|
212
453
|
get connectedPeerIds(): string[];
|
|
213
454
|
/** Send a pre-serialised blob message to a specific peer. Returns false
|
|
@@ -17,12 +17,23 @@
|
|
|
17
17
|
* does not mistake a sync fragment for a blob chunk.
|
|
18
18
|
*/
|
|
19
19
|
/** Maximum bytes a single channel.send may carry without fragmentation.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* Werift (the node-side WebRTC implementation polly recommends for
|
|
21
|
+
* CLI/daemon use) enforces a hard 64 KiB (65536 bytes) maxMessageSize
|
|
22
|
+
* on its RTCDataChannel — anything larger is rejected with a
|
|
23
|
+
* `max-message-size exceeded` error and silently drops the channel
|
|
24
|
+
* for that send. Chrome's SCTP cap is 256 KiB and would tolerate
|
|
25
|
+
* larger frames, but the threshold is chosen to fit inside werift's
|
|
26
|
+
* cap WITH per-fragment header overhead included so a single mesh
|
|
27
|
+
* deployment works on both transports. Matches the blob-transfer
|
|
28
|
+
* chunk size so the two transports have a consistent per-message
|
|
29
|
+
* footprint on the data channel. */
|
|
24
30
|
export declare const SYNC_FRAGMENT_THRESHOLD: number;
|
|
25
|
-
/** Chunk size used when a message exceeds the threshold.
|
|
31
|
+
/** Chunk size used when a message exceeds the threshold. Left at the
|
|
32
|
+
* same value as {@link SYNC_FRAGMENT_THRESHOLD} so the framing
|
|
33
|
+
* header (a JSON-encoded `SyncFragmentHeader` of ~90 bytes plus a
|
|
34
|
+
* 4-byte length prefix) does not push any fragment over werift's
|
|
35
|
+
* 64 KiB wire limit — see polly issue #104 for the failure mode
|
|
36
|
+
* this guards against. */
|
|
26
37
|
export declare const SYNC_FRAGMENT_CHUNK_SIZE: number;
|
|
27
38
|
export interface SyncFragmentHeader {
|
|
28
39
|
type: "sync-fragment";
|
|
@@ -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
|