@fairfox/polly 0.69.0 → 0.71.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/client/index.js +17 -20
- package/dist/src/client/index.js.map +4 -4
- package/dist/src/mesh.js +462 -154
- package/dist/src/mesh.js.map +9 -7
- package/dist/src/peer.js +153 -9
- package/dist/src/peer.js.map +5 -4
- package/dist/src/polly-ui/markdown.js +3 -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-diagnostics.d.ts +129 -0
- package/dist/src/shared/lib/mesh-network-adapter.d.ts +90 -3
- package/dist/src/shared/lib/revocation-summary.d.ts +54 -0
- package/dist/tools/test/src/e2e-mesh/console-allowlist.d.ts +31 -0
- package/dist/tools/test/src/e2e-mesh/index.d.ts +27 -0
- package/dist/tools/test/src/e2e-mesh/index.js +1183 -0
- package/dist/tools/test/src/e2e-mesh/index.js.map +22 -0
- package/dist/tools/test/src/e2e-mesh/keys.d.ts +55 -0
- package/dist/tools/test/src/e2e-mesh/launch-peer.d.ts +98 -0
- package/dist/tools/test/src/e2e-mesh/mesh-assertions.d.ts +53 -0
- package/dist/tools/test/src/e2e-mesh/serve-consumer.d.ts +32 -0
- package/dist/tools/test/src/e2e-mesh/wait-for-convergence.d.ts +38 -0
- package/dist/tools/test/src/e2e-mesh/with-relay.d.ts +53 -0
- package/dist/tools/test/src/visual/index.js +24 -24
- package/dist/tools/test/src/visual/index.js.map +2 -2
- package/dist/tools/verify/src/cli.js +361 -22
- package/dist/tools/verify/src/cli.js.map +6 -6
- package/dist/tools/verify/src/config.d.ts +26 -1
- package/dist/tools/verify/src/config.js +9 -1
- package/dist/tools/verify/src/config.js.map +4 -4
- package/dist/tools/verify/src/primitives/index.d.ts +30 -0
- package/dist/tools/visualize/src/cli.js +43 -1
- package/dist/tools/visualize/src/cli.js.map +3 -3
- package/package.json +11 -8
- package/LICENSE +0 -21
- package/README.md +0 -362
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mesh-diagnostics — typed event stream for observable mesh failures and
|
|
3
|
+
* state transitions.
|
|
4
|
+
*
|
|
5
|
+
* The mesh network adapter's incoming path has seven branches that drop a
|
|
6
|
+
* message and return undefined: a malformed signed envelope, a revoked
|
|
7
|
+
* peer, an unknown peer, a bad signature, a malformed encrypted envelope,
|
|
8
|
+
* a missing document key, and a bad decryption. Each branch is correct —
|
|
9
|
+
* the adapter must not surface tampered or unidentifiable bytes to the
|
|
10
|
+
* Repo — but the drop is invisible to anything observing the application.
|
|
11
|
+
* The classic symptom is "the other peer typed something and nothing
|
|
12
|
+
* arrived" with no error anywhere.
|
|
13
|
+
*
|
|
14
|
+
* This module exposes a typed emit-and-subscribe stream that the adapter
|
|
15
|
+
* (and the pairing and revocation paths) write to. Tests subscribe to
|
|
16
|
+
* assert that exactly the expected diagnostics fired and no others;
|
|
17
|
+
* production code can attach an observability sink that turns the stream
|
|
18
|
+
* into telemetry or a user-visible diagnostic surface.
|
|
19
|
+
*
|
|
20
|
+
* The stream is module-level. Listeners are deduplicated by reference;
|
|
21
|
+
* subscribe returns an unsubscribe function. Listener exceptions are
|
|
22
|
+
* caught and dropped so a buggy observer cannot tear the network path.
|
|
23
|
+
*/
|
|
24
|
+
/** All diagnostic event kinds, discriminated by the `kind` field. */
|
|
25
|
+
export type MeshDiagnostic = {
|
|
26
|
+
kind: "drop:malformed-signed-envelope";
|
|
27
|
+
reason?: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "drop:revoked-peer";
|
|
30
|
+
senderId: string;
|
|
31
|
+
} | {
|
|
32
|
+
kind: "drop:unknown-peer";
|
|
33
|
+
senderId: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "drop:bad-signature";
|
|
36
|
+
senderId: string;
|
|
37
|
+
reason?: string;
|
|
38
|
+
} | {
|
|
39
|
+
kind: "drop:malformed-encrypted-envelope";
|
|
40
|
+
senderId: string;
|
|
41
|
+
reason?: string;
|
|
42
|
+
} | {
|
|
43
|
+
kind: "drop:missing-doc-key";
|
|
44
|
+
senderId: string;
|
|
45
|
+
documentId: string;
|
|
46
|
+
} | {
|
|
47
|
+
kind: "drop:bad-decryption";
|
|
48
|
+
senderId: string;
|
|
49
|
+
documentId: string;
|
|
50
|
+
reason?: string;
|
|
51
|
+
} | {
|
|
52
|
+
kind: "drop:unknown-control-type";
|
|
53
|
+
senderId: string;
|
|
54
|
+
tag: number;
|
|
55
|
+
} | {
|
|
56
|
+
kind: "drop:empty-control-payload";
|
|
57
|
+
senderId: string;
|
|
58
|
+
} | {
|
|
59
|
+
kind: "drop:control-handler-threw";
|
|
60
|
+
senderId: string;
|
|
61
|
+
tag: number;
|
|
62
|
+
reason: string;
|
|
63
|
+
} | {
|
|
64
|
+
kind: "ctrl:revocation-received";
|
|
65
|
+
senderId: string;
|
|
66
|
+
} | {
|
|
67
|
+
kind: "ctrl:revocation-summary-received";
|
|
68
|
+
senderId: string;
|
|
69
|
+
} | {
|
|
70
|
+
kind: "revoke:duplicate";
|
|
71
|
+
revokedPeerId: string;
|
|
72
|
+
issuerId: string;
|
|
73
|
+
} | {
|
|
74
|
+
kind: "revoke:rejected";
|
|
75
|
+
senderId: string;
|
|
76
|
+
reason: string;
|
|
77
|
+
} | {
|
|
78
|
+
kind: "revoke:self-targeted";
|
|
79
|
+
issuerId: string;
|
|
80
|
+
reason?: string;
|
|
81
|
+
issuedAt: number;
|
|
82
|
+
} | {
|
|
83
|
+
kind: "pair:invite-issued";
|
|
84
|
+
peerId: string;
|
|
85
|
+
} | {
|
|
86
|
+
kind: "pair:invite-accepted";
|
|
87
|
+
peerId: string;
|
|
88
|
+
issuerId: string;
|
|
89
|
+
} | {
|
|
90
|
+
kind: "revoke:issued";
|
|
91
|
+
revokedPeerId: string;
|
|
92
|
+
issuerId: string;
|
|
93
|
+
} | {
|
|
94
|
+
kind: "revoke:applied";
|
|
95
|
+
revokedPeerId: string;
|
|
96
|
+
};
|
|
97
|
+
/** A diagnostic event with the wall-clock timestamp the emitter stamped. */
|
|
98
|
+
export type MeshDiagnosticEvent = MeshDiagnostic & {
|
|
99
|
+
timestamp: number;
|
|
100
|
+
};
|
|
101
|
+
/** Callback shape for subscribers. */
|
|
102
|
+
export type MeshDiagnosticListener = (event: MeshDiagnosticEvent) => void;
|
|
103
|
+
/**
|
|
104
|
+
* Emit a diagnostic to every active subscriber. Synchronous. Listener
|
|
105
|
+
* exceptions are swallowed.
|
|
106
|
+
*/
|
|
107
|
+
export declare function emitMeshDiagnostic(diagnostic: MeshDiagnostic): void;
|
|
108
|
+
/**
|
|
109
|
+
* Subscribe a listener. Returns an unsubscribe function. Idempotent on
|
|
110
|
+
* the same listener reference — subscribing the same function twice
|
|
111
|
+
* registers it once.
|
|
112
|
+
*/
|
|
113
|
+
export declare function subscribeToMeshDiagnostics(listener: MeshDiagnosticListener): () => void;
|
|
114
|
+
/**
|
|
115
|
+
* Convenience for tests and trace recorders: subscribe, collect every
|
|
116
|
+
* event into an array, return the array and a stop function that
|
|
117
|
+
* unsubscribes. The returned array is the live capture buffer — reads
|
|
118
|
+
* see new events the moment they fire.
|
|
119
|
+
*/
|
|
120
|
+
export declare function recordMeshDiagnostics(): {
|
|
121
|
+
events: ReadonlyArray<MeshDiagnosticEvent>;
|
|
122
|
+
stop: () => void;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Test-only: drop every subscriber. Use in `afterEach` to guarantee
|
|
126
|
+
* isolation between tests when a stop function was missed. Not exported
|
|
127
|
+
* from the mesh subpath in production builds — tests reach in directly.
|
|
128
|
+
*/
|
|
129
|
+
export declare function clearMeshDiagnosticListeners(): void;
|
|
@@ -45,6 +45,41 @@ import { type SigningKeyPair } from "./signing";
|
|
|
45
45
|
* encryption mode. See the file-level comment for the per-document key
|
|
46
46
|
* follow-up. */
|
|
47
47
|
export declare const DEFAULT_MESH_KEY_ID = "polly-mesh-default";
|
|
48
|
+
/**
|
|
49
|
+
* Control-message type tags. Every mesh message carries a single tag
|
|
50
|
+
* byte at the front of its plaintext payload, after decryption and
|
|
51
|
+
* signature verification. The tag discriminates the inner contents so
|
|
52
|
+
* future control flows (RFC-043 revocation propagation, future RFCs)
|
|
53
|
+
* can share the same encrypted-signed envelope without re-versioning.
|
|
54
|
+
*
|
|
55
|
+
* 0x00 is the default Automerge sync-message channel that polly has
|
|
56
|
+
* carried since the first cut. 0x01 and 0x02 are reserved for the
|
|
57
|
+
* revocation flow designed in RFC-043; the adapter recognises them at
|
|
58
|
+
* receive time but does not yet act on the payload — that lands in
|
|
59
|
+
* the second RFC-043 PR. Tags 0x03 and above are unassigned; a
|
|
60
|
+
* receiver that sees one emits `drop:unknown-control-type` and the
|
|
61
|
+
* message is dropped.
|
|
62
|
+
*
|
|
63
|
+
* Wire format break: polly 0.70 and earlier do not prepend the tag
|
|
64
|
+
* and do not strip it on receive. Mixing 0.70 and 0.71-plus peers on
|
|
65
|
+
* the same mesh produces garbage on both sides. The break is
|
|
66
|
+
* acknowledged in RFC-043 and required for the protocol-level
|
|
67
|
+
* revocation feature; the alternative (a separate WebRTC data
|
|
68
|
+
* channel) doubles transport complexity.
|
|
69
|
+
*/
|
|
70
|
+
export declare const MESH_CONTROL_TYPE: {
|
|
71
|
+
/** Automerge sync message — the default channel. */
|
|
72
|
+
readonly Sync: 0;
|
|
73
|
+
/** A signed RevocationRecord (RFC-043). Receive-side dispatch is
|
|
74
|
+
* wired in this PR; the apply-and-persist behaviour lands in the
|
|
75
|
+
* next RFC-043 PR. */
|
|
76
|
+
readonly Revocation: 1;
|
|
77
|
+
/** A revocation-set summary exchanged on every new peer connection
|
|
78
|
+
* to gossip revocations to peers that were offline at issue-time
|
|
79
|
+
* (RFC-043). Same staging as Revocation. */
|
|
80
|
+
readonly RevocationSummary: 2;
|
|
81
|
+
};
|
|
82
|
+
export type MeshControlType = (typeof MESH_CONTROL_TYPE)[keyof typeof MESH_CONTROL_TYPE];
|
|
48
83
|
/**
|
|
49
84
|
* A mesh keyring holds the local peer's signing identity, the public keys
|
|
50
85
|
* of every peer the local node will accept messages from, the symmetric
|
|
@@ -106,6 +141,22 @@ export interface MeshNetworkAdapterOptions {
|
|
|
106
141
|
* messages. Defaults to true (encrypt + sign, the full $meshState
|
|
107
142
|
* posture). */
|
|
108
143
|
encryptionEnabled?: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Optional handler for non-Sync control messages (RFC-043). Called
|
|
146
|
+
* after signature verification and decryption with the type tag,
|
|
147
|
+
* the body bytes that followed the tag, and the verified senderId.
|
|
148
|
+
* The handler owns the apply-and-persist behaviour for whichever
|
|
149
|
+
* control flow the tag belongs to; the adapter routes only.
|
|
150
|
+
*
|
|
151
|
+
* The handler is called *after* the corresponding `ctrl:*-received`
|
|
152
|
+
* diagnostic fires, so subscribers observing the low-level signal
|
|
153
|
+
* see the event before the handler mutates any application state.
|
|
154
|
+
* Handler exceptions are swallowed by the adapter — a buggy handler
|
|
155
|
+
* cannot tear the network path — but a diagnostic
|
|
156
|
+
* `drop:control-handler-threw` is emitted so the failure is
|
|
157
|
+
* observable.
|
|
158
|
+
*/
|
|
159
|
+
onControlMessage?: (tag: number, body: Uint8Array, senderId: string) => void;
|
|
109
160
|
}
|
|
110
161
|
/**
|
|
111
162
|
* NetworkAdapter that wraps another adapter with Polly's mesh-transport
|
|
@@ -121,6 +172,7 @@ export declare class MeshNetworkAdapter extends NetworkAdapter {
|
|
|
121
172
|
readonly base: NetworkAdapter;
|
|
122
173
|
readonly keyringSource: () => MeshKeyring;
|
|
123
174
|
readonly encryptionEnabled: boolean;
|
|
175
|
+
readonly onControlMessage: ((tag: number, body: Uint8Array, senderId: string) => void) | undefined;
|
|
124
176
|
/** Read-only view of the current keyring. Each access calls
|
|
125
177
|
* {@link MeshNetworkAdapterOptions.keyringSource}, so the value
|
|
126
178
|
* reflects whatever mutations or swaps the caller has applied since
|
|
@@ -137,11 +189,46 @@ export declare class MeshNetworkAdapter extends NetworkAdapter {
|
|
|
137
189
|
* Wrap an outgoing Automerge message in an encrypt-then-sign envelope.
|
|
138
190
|
* The wrapped payload is returned as a Message with the original sender
|
|
139
191
|
* and target ids and the crypto blob in the `data` field.
|
|
192
|
+
*
|
|
193
|
+
* The serialised Automerge message is prefixed with a one-byte
|
|
194
|
+
* control-type tag (RFC-043). For outgoing Automerge sync this is
|
|
195
|
+
* always {@link MESH_CONTROL_TYPE.Sync} (0x00); the tag exists so
|
|
196
|
+
* future control flows (revocation propagation, revocation-set
|
|
197
|
+
* summaries) can share the same encrypted-signed envelope without
|
|
198
|
+
* re-versioning the wire format.
|
|
140
199
|
*/
|
|
141
200
|
private wrap;
|
|
201
|
+
private tryUnwrap;
|
|
142
202
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
203
|
+
* Dispatch a verified-and-decrypted plaintext payload based on its
|
|
204
|
+
* one-byte control-type tag (RFC-043). For {@link MESH_CONTROL_TYPE.Sync}
|
|
205
|
+
* the remainder is the serialised Automerge message and is returned
|
|
206
|
+
* to the caller. For revocation tags the dispatch emits a
|
|
207
|
+
* `ctrl:*-received` diagnostic and drops the payload at this layer
|
|
208
|
+
* pending the next RFC-043 PR. Unknown tags emit
|
|
209
|
+
* `drop:unknown-control-type` and drop.
|
|
145
210
|
*/
|
|
146
|
-
private
|
|
211
|
+
private dispatchTaggedPayload;
|
|
212
|
+
private invokeControlHandler;
|
|
213
|
+
/**
|
|
214
|
+
* Send a control message (RFC-043) to a list of connected peers.
|
|
215
|
+
* The body is wrapped in the same encrypt-sign envelope Automerge
|
|
216
|
+
* sync uses; the type tag goes in front so receivers route it to
|
|
217
|
+
* {@link MeshNetworkAdapterOptions.onControlMessage}.
|
|
218
|
+
*
|
|
219
|
+
* The base adapter does not surface its connected-peer set on the
|
|
220
|
+
* NetworkAdapter interface, so the caller passes the targets
|
|
221
|
+
* explicitly. The MeshClient layer maintains that list from the
|
|
222
|
+
* `peer-candidate` / `peer-disconnected` events.
|
|
223
|
+
*/
|
|
224
|
+
sendControlMessage(tag: MeshControlType, body: Uint8Array, targetPeerIds: ReadonlyArray<PeerId>): void;
|
|
147
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Prepend a one-byte control-type tag to a payload. The tag goes
|
|
228
|
+
* inside the encrypted-signed envelope (or directly inside the signed
|
|
229
|
+
* envelope in sign-only mode), so it is both confidential (encrypted
|
|
230
|
+
* when encryption is enabled) and authenticated (covered by the
|
|
231
|
+
* signature). Exposed so future RFC-043 issue helpers can build
|
|
232
|
+
* tagged payloads without rebuilding this primitive.
|
|
233
|
+
*/
|
|
234
|
+
export declare function prependControlTag(tag: MeshControlType, body: Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* revocation-summary — RFC-043 wire format for the revocation-set
|
|
3
|
+
* summary exchanged on every new peer connection.
|
|
4
|
+
*
|
|
5
|
+
* On a fresh data channel both peers send the other a summary of
|
|
6
|
+
* every revocation they currently hold. After exchange each side
|
|
7
|
+
* computes which entries in its own set are missing from the
|
|
8
|
+
* remote's summary, and pushes those entries as full encoded
|
|
9
|
+
* revocation blobs (tag 0x01). The summary itself is informative,
|
|
10
|
+
* not authoritative — only the signed blob can mutate a keyring.
|
|
11
|
+
*
|
|
12
|
+
* Wire format: UTF-8 JSON. A summary is a sorted JSON array of
|
|
13
|
+
* entries, each carrying the fields needed to detect set-difference
|
|
14
|
+
* without leaking the blob's signature. Sorting is canonical so two
|
|
15
|
+
* peers comparing summaries agree on order even when their stores
|
|
16
|
+
* were populated in different sequences.
|
|
17
|
+
*
|
|
18
|
+
* [
|
|
19
|
+
* { "r": "<revokedPeerId>", "i": "<issuerPeerId>", "t": <issuedAt> },
|
|
20
|
+
* ...
|
|
21
|
+
* ]
|
|
22
|
+
*
|
|
23
|
+
* Short field names keep the wire compact for keyrings with many
|
|
24
|
+
* revocations. Long-form parsing isn't a goal — the format is
|
|
25
|
+
* internal to the mesh protocol.
|
|
26
|
+
*/
|
|
27
|
+
/** A single entry in a revocation-set summary. */
|
|
28
|
+
export interface RevocationSummaryEntry {
|
|
29
|
+
/** Peer id the revocation targets. */
|
|
30
|
+
revokedPeerId: string;
|
|
31
|
+
/** Peer id that issued the revocation. */
|
|
32
|
+
issuerPeerId: string;
|
|
33
|
+
/** Unix milliseconds at issue time, from the underlying RevocationRecord. */
|
|
34
|
+
issuedAt: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Encode a list of revocation entries to the canonical wire
|
|
38
|
+
* representation. Entries are sorted by `revokedPeerId` then
|
|
39
|
+
* `issuerPeerId` then `issuedAt` to make the comparison
|
|
40
|
+
* order-independent.
|
|
41
|
+
*/
|
|
42
|
+
export declare function encodeRevocationSummary(entries: ReadonlyArray<RevocationSummaryEntry>): Uint8Array;
|
|
43
|
+
/**
|
|
44
|
+
* Inverse of {@link encodeRevocationSummary}. Throws on malformed
|
|
45
|
+
* input — the caller is expected to drop the summary and emit a
|
|
46
|
+
* diagnostic when this happens, not retry.
|
|
47
|
+
*/
|
|
48
|
+
export declare function decodeRevocationSummary(bytes: Uint8Array): RevocationSummaryEntry[];
|
|
49
|
+
/**
|
|
50
|
+
* Stable key for a summary entry. Two entries with the same key
|
|
51
|
+
* represent the same logical revocation. Used by the
|
|
52
|
+
* peer-candidate gossip path to compute set differences.
|
|
53
|
+
*/
|
|
54
|
+
export declare function summaryEntryKey(entry: RevocationSummaryEntry): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fairfox/polly/test/e2e-mesh — canonical console-noise allowlist.
|
|
3
|
+
*
|
|
4
|
+
* Mesh runs emit a small number of benign console lines (Repo lifecycle,
|
|
5
|
+
* Automerge warmup, occasional sync diagnostics). E2e scripts watch the
|
|
6
|
+
* Puppeteer console stream and fail on anything unexpected; without an
|
|
7
|
+
* allowlist every run trips on the same benign noise.
|
|
8
|
+
*
|
|
9
|
+
* The allowlist is owned by polly because polly knows which lines its
|
|
10
|
+
* own code produces. Consumers extend it with their app-specific noise.
|
|
11
|
+
* Entries are tested as substrings against the rendered console message.
|
|
12
|
+
*/
|
|
13
|
+
/** Match a console line that contains the given substring. */
|
|
14
|
+
export interface ConsolePattern {
|
|
15
|
+
/** Optional console level filter — "log" | "info" | "warn" | "error".
|
|
16
|
+
* Undefined matches any level. */
|
|
17
|
+
level?: "log" | "info" | "warn" | "error";
|
|
18
|
+
/** Substring or RegExp the rendered console line must satisfy. */
|
|
19
|
+
match: string | RegExp;
|
|
20
|
+
/** Short reason — surfaces in failure messages when the allowlist
|
|
21
|
+
* evolves and an entry should be removed. */
|
|
22
|
+
reason: string;
|
|
23
|
+
}
|
|
24
|
+
export declare const MESH_CONSOLE_ALLOWLIST: ReadonlyArray<ConsolePattern>;
|
|
25
|
+
/**
|
|
26
|
+
* Return true when the console line matches any allowlist entry.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isAllowedConsoleLine(line: {
|
|
29
|
+
level: string;
|
|
30
|
+
text: string;
|
|
31
|
+
}, allowlist?: ReadonlyArray<ConsolePattern>): boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fairfox/polly/test/e2e-mesh — end-to-end test kit for the mesh.
|
|
3
|
+
*
|
|
4
|
+
* Centralises the patterns every consumer's e2e scripts reinvent today:
|
|
5
|
+
* pairing-ceremony driving, convergence polling, console-noise filtering,
|
|
6
|
+
* screenshot-on-failure, and an embedded signalling relay. Fairfox and
|
|
7
|
+
* lingua import from this subpath rather than reimplementing.
|
|
8
|
+
*
|
|
9
|
+
* The kit is opinionated about the shape of the consumer it drives —
|
|
10
|
+
* pairing UI exposes stable `data-e2e-*` attributes, the bootstrap path
|
|
11
|
+
* goes through `createMeshClient`, the document state is observable via
|
|
12
|
+
* a polled DOM predicate. Consumers that follow the conventions get the
|
|
13
|
+
* full kit for free; those that diverge supply their own driver per
|
|
14
|
+
* primitive.
|
|
15
|
+
*
|
|
16
|
+
* Diagnostic obligation runs by default through {@link startDiagnosticRecorder}:
|
|
17
|
+
* unexpected silent drops on the diagnostic stream fail the script. A
|
|
18
|
+
* scenario that legitimately exercises a drop branch (e.g. revocation)
|
|
19
|
+
* passes the expected kinds to `assertNoSilentDrops({ allow: [...] })`.
|
|
20
|
+
*/
|
|
21
|
+
export { type ConsolePattern, isAllowedConsoleLine, MESH_CONSOLE_ALLOWLIST, } from "./console-allowlist";
|
|
22
|
+
export { knownPeersFor, type PrebakedKeyringPair, type PrebakedKeyringSet, type PrebakedPeer, prebakeKeyringPair, prebakeKeyringSet, } from "./keys";
|
|
23
|
+
export { type CapturedConsoleLine, type LaunchedPeer, type LaunchPeerOptions, type LaunchSecondTabOptions, launchPeer, launchSecondTab, } from "./launch-peer";
|
|
24
|
+
export { type DiagnosticRecorder, MeshAssertionError, type MeshAssertionFailure, startDiagnosticRecorder, } from "./mesh-assertions";
|
|
25
|
+
export { type ServeConsumerOptions, type ServeConsumerResult, serveConsumer, } from "./serve-consumer";
|
|
26
|
+
export { type ConvergencePredicate, type PeerSnapshot, type WaitForConvergenceOptions, waitForConvergence, waitForMeshConnected, } from "./wait-for-convergence";
|
|
27
|
+
export { type WithRelayOptions, type WithRelayResult, withRelay } from "./with-relay";
|