@peerbit/stream 5.0.16 → 5.1.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.
@@ -0,0 +1,696 @@
1
+ // Interfaces for the optional native (wasm) DirectStream core implemented by
2
+ // `@peerbit/network-rust` (the `peerbit_wire` crate's `direct_stream`
3
+ // modules). When `DirectStreamOptions.rustCore` is set, the routing table,
4
+ // seen-cache dedup, outbound lane scheduling and the seek-routing/relay/ack
5
+ // decisions run in Rust; the TS class remains the socket owner and byte
6
+ // pump. With the option unset the pure TS implementations are used,
7
+ // unchanged.
8
+ import type { Uint8ArrayList } from "uint8arraylist";
9
+ import type { PushableLanes } from "./pushable-lanes.js";
10
+ import type { RoutesLike } from "./routes.js";
11
+
12
+ /**
13
+ * Native (wasm) batch decode+verify module for inbound frames, implemented by
14
+ * `@peerbit/network-rust`. The result is a flat Uint32Array with
15
+ * NATIVE_WIRE_RECORD_WORDS words per frame; the layout is defined by the
16
+ * `peerbit_wire` crate (see RECORD_* in its lib.rs) and mirrored by the
17
+ * NATIVE_WIRE_* constants in index.ts.
18
+ */
19
+ export interface NativeWire {
20
+ decodeAndVerifyBatch(frames: Uint8Array[], nowMs: number): Uint32Array;
21
+ }
22
+
23
+ /** Seen-cache dedup counter backed by the native core. */
24
+ export interface RustSeenCache {
25
+ /**
26
+ * Bump the seen counter for a frame and return how many times it was seen
27
+ * before. `kind` 0 keys by message id (first 33 frame bytes, the
28
+ * `getMsgId` rule), 1 by sha256 of the whole frame (the ACK path).
29
+ */
30
+ modify(bytes: Uint8Array, kind: 0 | 1): number;
31
+ clear(): void;
32
+ }
33
+
34
+ /** Routing/relay/ack decision functions executed by the native core. */
35
+ export interface RustStreamDecisions {
36
+ shouldIgnoreData(args: {
37
+ seenBefore: number;
38
+ acknowledgedMode: boolean;
39
+ redundancy: number;
40
+ hops: string[];
41
+ me: string;
42
+ signedBySelf: boolean;
43
+ }): boolean;
44
+ shouldAcknowledge(args: {
45
+ isRecipient: boolean;
46
+ seenBefore: number;
47
+ redundancy: number;
48
+ }): boolean;
49
+ ackNextHop(
50
+ trace: string[],
51
+ me: string,
52
+ ): { myIndex: number; next?: string };
53
+ seekAckRouteUpdate(args: {
54
+ current: string;
55
+ upstream?: string;
56
+ downstream: string;
57
+ }): { from: string; neighbour: string };
58
+ filterFloodTargets(
59
+ candidates: string[],
60
+ from: string,
61
+ signed: string[],
62
+ hops: string[],
63
+ ): Uint32Array;
64
+ filterSilentRelayRecipients(
65
+ recipients: string[],
66
+ me: string,
67
+ from: string,
68
+ connected: string[],
69
+ hops: string[],
70
+ ): string[];
71
+ selectRedundancyProbes(
72
+ peers: string[],
73
+ used: string[],
74
+ redundancy: number,
75
+ ): string[];
76
+ }
77
+
78
+ export interface RustRoutesInit {
79
+ me: string;
80
+ routeMaxRetentionPeriod: number;
81
+ signal?: AbortSignal;
82
+ maxFromEntries?: number;
83
+ maxTargetsPerFrom?: number;
84
+ maxRelaysPerTarget?: number;
85
+ }
86
+
87
+ export interface RustLanesInit {
88
+ lanes: number;
89
+ maxBufferedBytes?: number;
90
+ onBufferSize?(bufferedBytes: number): void;
91
+ onPush?(value: { byteLength: number }, lane: number): void;
92
+ }
93
+
94
+ /** A decoded `/peerbit/direct-block` message produced by the native codec. */
95
+ export type RustDecodedBlockMessage =
96
+ | { type: "request"; cid: string }
97
+ | {
98
+ type: "response";
99
+ cid: string;
100
+ /** View into the input payload (no copy). */
101
+ bytes: Uint8Array;
102
+ };
103
+
104
+ /**
105
+ * Provider-hint cache of `RemoteBlocks` backed by the native core
106
+ * (`rememberProvider`/`rememberProviderHints`/lookup semantics).
107
+ */
108
+ export interface RustBlockProviderCache {
109
+ get(cid: string): string[] | undefined;
110
+ rememberProvider(cid: string, provider: string): void;
111
+ rememberHints(cid: string, providers: string[]): void;
112
+ clear(): void;
113
+ }
114
+
115
+ /**
116
+ * Eager-block cache with native bookkeeping. Block bytes stay host-side;
117
+ * the native index decides retention/eviction.
118
+ */
119
+ export interface RustEagerBlockCache {
120
+ add(cid: string, bytes: Uint8Array): void;
121
+ get(cid: string): Uint8Array | undefined;
122
+ del(cid: string): void;
123
+ clear(): void;
124
+ }
125
+
126
+ /**
127
+ * Native block-exchange components for `DirectBlock`/`RemoteBlocks`
128
+ * (`@peerbit/blocks`): the `BlockMessage` codec, the provider resolution
129
+ * rules and the caches. Part of the same rust-core mode as the DirectStream
130
+ * state machine.
131
+ */
132
+ export interface RustBlockExchange {
133
+ encodeBlockRequest(cid: string): Uint8Array;
134
+ encodeBlockResponse(cid: string, bytes: Uint8Array): Uint8Array;
135
+ decodeBlockMessage(payload: Uint8Array): RustDecodedBlockMessage;
136
+ normalizeProviderHints(
137
+ providers: string[],
138
+ me: string,
139
+ limit: number,
140
+ ): string[];
141
+ pickRequestBatch(providers: string[], me: string, attempt: number): string[];
142
+ defaultProviderCandidates(
143
+ negotiated: string[],
144
+ connected: string[],
145
+ me: string,
146
+ ): string[];
147
+ createProviderCache(init: {
148
+ me: string;
149
+ maxEntries: number;
150
+ ttlMs: number;
151
+ maxProvidersPerCid: number;
152
+ }): RustBlockProviderCache;
153
+ createEagerCache(init: { max: number; ttl: number }): RustEagerBlockCache;
154
+ }
155
+
156
+ /**
157
+ * A decoded `/peerbit/topic-control-plane` message produced by the native
158
+ * codec (borsh `PubSubMessage` variants 0-7).
159
+ */
160
+ export type RustDecodedPubSubMessage =
161
+ | {
162
+ type: "data";
163
+ topics: string[];
164
+ strict: boolean;
165
+ /** View into the input payload (no copy). */
166
+ data: Uint8Array;
167
+ }
168
+ | { type: "subscribe"; topics: string[]; requestSubscribers: boolean }
169
+ | { type: "unsubscribe"; topics: string[] }
170
+ | { type: "get-subscribers"; topics: string[] }
171
+ | { type: "topic-root-candidates"; candidates: string[] }
172
+ | {
173
+ type: "peer-unavailable";
174
+ publicKeyHash: string;
175
+ session: bigint;
176
+ timestamp: bigint;
177
+ topics: string[];
178
+ }
179
+ | { type: "topic-root-query"; requestId: number; topic: string }
180
+ | {
181
+ type: "topic-root-query-response";
182
+ requestId: number;
183
+ topic: string;
184
+ root?: string;
185
+ };
186
+
187
+ /**
188
+ * `TopicRootDirectory` root-resolution state backed by the native core
189
+ * (explicit per-topic roots plus the normalized deterministic candidate
190
+ * set). Trackers and the resolver callback stay host-side.
191
+ */
192
+ export interface RustTopicRootDirectoryState {
193
+ setRoot(topic: string, root: string): void;
194
+ deleteRoot(topic: string): void;
195
+ getRoot(topic: string): string | undefined;
196
+ setDefaultCandidates(candidates: string[]): void;
197
+ getDefaultCandidates(): string[];
198
+ resolveDeterministicCandidate(topic: string): string | undefined;
199
+ }
200
+
201
+ /**
202
+ * Native topic-control-plane components consumed by `@peerbit/pubsub`: the
203
+ * `PubSubMessage` codec, the topic hashing that keys shard mapping and
204
+ * deterministic root selection, the root-directory state and the
205
+ * subscribe-state convergence rules. The observable subscription maps stay
206
+ * host-side (they are public API); every protocol decision that feeds them
207
+ * runs natively.
208
+ */
209
+ export interface RustTopicControl {
210
+ encodePubSubData(
211
+ topics: string[],
212
+ strict: boolean,
213
+ data: Uint8Array,
214
+ ): Uint8Array;
215
+ encodeSubscribe(topics: string[], requestSubscribers: boolean): Uint8Array;
216
+ encodeUnsubscribe(topics: string[]): Uint8Array;
217
+ encodeGetSubscribers(topics: string[]): Uint8Array;
218
+ encodeTopicRootCandidates(candidates: string[]): Uint8Array;
219
+ encodePeerUnavailable(
220
+ publicKeyHash: string,
221
+ session: bigint,
222
+ timestamp: bigint,
223
+ topics: string[],
224
+ ): Uint8Array;
225
+ encodeTopicRootQuery(requestId: number, topic: string): Uint8Array;
226
+ encodeTopicRootQueryResponse(
227
+ requestId: number,
228
+ topic: string,
229
+ root?: string,
230
+ ): Uint8Array;
231
+ decodePubSubMessage(payload: Uint8Array): RustDecodedPubSubMessage;
232
+ /** `getShardTopicForUserTopic`: user topic -> internal shard topic. */
233
+ shardTopic(topic: string, shardCount: number, prefix: string): string;
234
+ /**
235
+ * `normalizeAutoTopicRootCandidates`: dedupe, include self, sort and cap
236
+ * at the auto-candidate bound.
237
+ */
238
+ normalizeAutoCandidates(candidates: string[], me: string): string[];
239
+ /**
240
+ * The `subscriptionStateIsLatest` comparison rule. `lasts` carries
241
+ * interleaved (session, timestamp) watermark pairs for the relevant
242
+ * topics that have one; the watermark write-back stays host-side.
243
+ */
244
+ subscriptionIsLatest(
245
+ lasts: BigUint64Array,
246
+ session: bigint,
247
+ timestamp: bigint,
248
+ ): boolean;
249
+ /**
250
+ * The subscribe-apply replacement rule: replace tracked subscription data
251
+ * for new subscribers or strictly newer sessions, else only refresh.
252
+ */
253
+ subscribeShouldReplace(
254
+ existingSession: bigint | undefined,
255
+ session: bigint,
256
+ ): boolean;
257
+ createRootDirectoryState(): RustTopicRootDirectoryState;
258
+ }
259
+
260
+ /** Decoded fanout-tree frames produced by the native codec. The decoders
261
+ * mirror the tolerance of the TS parsers exactly: `undefined` means the
262
+ * frame fails the same minimum-length checks, and truncated lists end at
263
+ * the same element. Multiaddr bytes are returned raw; validity filtering
264
+ * (and `multiaddr()` construction) stays host-side in both modes. */
265
+ export type RustDecodedFanoutJoinReq = {
266
+ reqId: number;
267
+ bidPerByte: number;
268
+ parentUpgradeReservationToken: number;
269
+ };
270
+
271
+ export type RustDecodedFanoutJoinAccept = {
272
+ parentLevel: number;
273
+ parentRouteFromRoot: string[];
274
+ haveRange?: { haveFrom: number; haveToExclusive: number };
275
+ };
276
+
277
+ export type RustDecodedFanoutJoinReject = {
278
+ reason: number;
279
+ redirects: { hash: string; addrs: Uint8Array[] }[];
280
+ };
281
+
282
+ export type RustDecodedFanoutUnicast = {
283
+ ackToken?: bigint;
284
+ route: string[];
285
+ replyRoute?: string[];
286
+ payloadOffset: number;
287
+ };
288
+
289
+ export type RustDecodedFanoutTrackerReplyEntry = {
290
+ hash: string;
291
+ level: number;
292
+ freeSlots: number;
293
+ bidPerByte: number;
294
+ addrs: Uint8Array[];
295
+ };
296
+
297
+ export type RustDecodedFanoutParentProbeReply = {
298
+ reqId: number;
299
+ hash: string;
300
+ rooted: boolean;
301
+ accepting: boolean;
302
+ repairing: boolean;
303
+ overloaded: boolean;
304
+ reservationToken: number;
305
+ level: number;
306
+ maxChildren: number;
307
+ freeSlots: number;
308
+ children: number;
309
+ haveToExclusive: number;
310
+ missingSeqs: number;
311
+ dataWriteDrops: number;
312
+ droppedForwards: number;
313
+ };
314
+
315
+ export type RustDecodedFanoutProviderEntry = {
316
+ hash: string;
317
+ addrs: Uint8Array[];
318
+ };
319
+
320
+ /** `normalizeParentUpgradePolicy` result shape (fanout-tree-parent-upgrade). */
321
+ export type RustParentUpgradePolicy = {
322
+ intervalMs: number;
323
+ leafOnly: boolean;
324
+ minLevelGain: number;
325
+ rootMinLevelGain: number;
326
+ rootMinSubtreeGain: number;
327
+ nonRootMinLevelGain: number;
328
+ minFreeSlots: number;
329
+ rootMinFreeSlots: number;
330
+ maxChildLoadRatio: number;
331
+ rootMaxChildLoadRatio: number;
332
+ staleRootProbeProbability: number;
333
+ cooldownMs: number;
334
+ quietMs: number;
335
+ repairQuietMs: number;
336
+ maxPerPeer: number;
337
+ repairGuard: boolean;
338
+ dataGuard: boolean;
339
+ mode: "direct" | "probe" | "shadow";
340
+ verifyStaleRootCapacity: boolean;
341
+ failedBackoff: { minMs: number; maxMs: number };
342
+ probe: {
343
+ timeoutMs: number;
344
+ maxPerRound: number;
345
+ maxLagMessages: number;
346
+ rejectCooldownMs: number;
347
+ rejectCooldownMaxMs: number;
348
+ };
349
+ shadow: {
350
+ observeMs: number;
351
+ minObservations: number;
352
+ dualPathMs: number;
353
+ dualPathMinMessages: number;
354
+ };
355
+ };
356
+
357
+ export type RustParentUpgradeOptions = {
358
+ parentUpgradeIntervalMs?: number;
359
+ parentUpgradeLeafOnly?: boolean;
360
+ parentUpgradeMinLevelGain?: number;
361
+ parentUpgradeRootMinLevelGain?: number;
362
+ parentUpgradeRootMinSubtreeGain?: number;
363
+ parentUpgradeNonRootMinLevelGain?: number;
364
+ parentUpgradeMinFreeSlots?: number;
365
+ parentUpgradeRootMinFreeSlots?: number;
366
+ parentUpgradeMaxChildLoadRatio?: number;
367
+ parentUpgradeRootMaxChildLoadRatio?: number;
368
+ parentUpgradeCooldownMs?: number;
369
+ parentUpgradeFailedBackoffMinMs?: number;
370
+ parentUpgradeFailedBackoffMaxMs?: number;
371
+ parentUpgradeQuietMs?: number;
372
+ parentUpgradeRepairQuietMs?: number;
373
+ parentUpgradeMaxPerPeer?: number;
374
+ parentUpgradeRepairGuard?: boolean;
375
+ parentUpgradeDataGuard?: boolean;
376
+ parentUpgradeMode?: string;
377
+ parentUpgradeVerifyStaleRootCapacity?: boolean;
378
+ parentUpgradeStaleRootProbeProbability?: number;
379
+ parentProbeTimeoutMs?: number;
380
+ parentProbeMaxPerRound?: number;
381
+ parentProbeMaxLagMessages?: number;
382
+ parentProbeRejectCooldownMs?: number;
383
+ parentProbeRejectCooldownMaxMs?: number;
384
+ parentShadowObserveMs?: number;
385
+ parentShadowMinObservations?: number;
386
+ parentShadowDualPathMs?: number;
387
+ parentShadowDualPathMinMessages?: number;
388
+ };
389
+
390
+ export type RustParentUpgradeGateState = {
391
+ children: { size: number };
392
+ missingSeqs: { size: number };
393
+ lastRepairSentAt: number;
394
+ endSeqExclusive: number;
395
+ parentUpgradeRetryAfterSeq: number;
396
+ maxSeqSeen: number;
397
+ parentUpgradeCount: number;
398
+ parentUpgradeBackoffUntil: number;
399
+ parentUpgradeLastAt: number;
400
+ lastParentDataAt: number;
401
+ lastParentUpgradeActivityAt?: number;
402
+ };
403
+
404
+ export type RustParentUpgradeGateOptions = {
405
+ leafOnly: boolean;
406
+ repairGuard: boolean;
407
+ dataGuard: boolean;
408
+ endedAndComplete: boolean;
409
+ maxPerPeer: number;
410
+ cooldownMs: number;
411
+ quietMs: number;
412
+ repairQuietMs: number;
413
+ now: number;
414
+ };
415
+
416
+ /**
417
+ * Native fanout-tree components consumed by `@peerbit/pubsub`'s FanoutTree
418
+ * in rust-core mode: the complete `/peerbit/fanout-tree/0.5.0` big-endian
419
+ * frame codec (byte-identical to `fanout-tree-codec.ts`, all message kinds
420
+ * MSG_JOIN_REQ(1)..MSG_PARENT_PROBE_REPLY(41)) plus the parent-upgrade
421
+ * policy/gate decisions merged in PR #911. The channel state machine,
422
+ * timers and events stay host-side.
423
+ */
424
+ export interface RustFanoutTree {
425
+ encodeJoinReq(
426
+ channelKey: Uint8Array,
427
+ reqId: number,
428
+ bidPerByte: number,
429
+ parentUpgradeReservationToken?: number,
430
+ ): Uint8Array;
431
+ encodeJoinAccept(
432
+ channelKey: Uint8Array,
433
+ reqId: number,
434
+ level: number,
435
+ parentRouteFromRoot?: string[],
436
+ haveRange?: { haveFrom: number; haveToExclusive: number },
437
+ ): Uint8Array;
438
+ encodeJoinReject(
439
+ channelKey: Uint8Array,
440
+ reqId: number,
441
+ reason: number,
442
+ redirects?: { hash: string; addrs: Uint8Array[] }[],
443
+ ): Uint8Array;
444
+ encodeKick(channelKey: Uint8Array): Uint8Array;
445
+ encodeEnd(channelKey: Uint8Array, lastSeqExclusive: number): Uint8Array;
446
+ encodeRepairReq(
447
+ channelKey: Uint8Array,
448
+ reqId: number,
449
+ missingSeqs: number[],
450
+ ): Uint8Array;
451
+ encodeFetchReq(
452
+ channelKey: Uint8Array,
453
+ reqId: number,
454
+ missingSeqs: number[],
455
+ ): Uint8Array;
456
+ encodeIHave(
457
+ channelKey: Uint8Array,
458
+ haveFrom: number,
459
+ haveToExclusive: number,
460
+ ): Uint8Array;
461
+ encodeData(payload: Uint8Array): Uint8Array;
462
+ encodePublishProxy(channelKey: Uint8Array, payload: Uint8Array): Uint8Array;
463
+ encodeLeave(channelKey: Uint8Array): Uint8Array;
464
+ encodeUnicast(
465
+ channelKey: Uint8Array,
466
+ route: string[],
467
+ payload: Uint8Array,
468
+ options?: { ackToken?: bigint; replyRoute?: string[] },
469
+ ): Uint8Array;
470
+ encodeUnicastAck(
471
+ channelKey: Uint8Array,
472
+ ackToken: bigint,
473
+ route: string[],
474
+ ): Uint8Array;
475
+ encodeRouteQuery(
476
+ channelKey: Uint8Array,
477
+ reqId: number,
478
+ targetHash: string,
479
+ ): Uint8Array;
480
+ encodeRouteReply(
481
+ channelKey: Uint8Array,
482
+ reqId: number,
483
+ route?: string[],
484
+ ): Uint8Array;
485
+ encodeTrackerAnnounce(
486
+ channelKey: Uint8Array,
487
+ ttlMs: number,
488
+ level: number,
489
+ maxChildren: number,
490
+ freeSlots: number,
491
+ bidPerByte: number,
492
+ addrs: { bytes: Uint8Array }[],
493
+ ): Uint8Array;
494
+ encodeTrackerQuery(
495
+ channelKey: Uint8Array,
496
+ reqId: number,
497
+ want: number,
498
+ ): Uint8Array;
499
+ encodeTrackerReply(
500
+ channelKey: Uint8Array,
501
+ reqId: number,
502
+ entries: {
503
+ hash: string;
504
+ level: number;
505
+ freeSlots: number;
506
+ bidPerByte: number;
507
+ addrs: Uint8Array[];
508
+ }[],
509
+ ): Uint8Array;
510
+ encodeTrackerFeedback(
511
+ channelKey: Uint8Array,
512
+ candidateHash: string,
513
+ event: number,
514
+ reason: number,
515
+ ): Uint8Array;
516
+ encodeParentProbeReq(
517
+ channelKey: Uint8Array,
518
+ reqId: number,
519
+ minFreeSlots?: number,
520
+ reserveRootCapacity?: boolean,
521
+ ): Uint8Array;
522
+ encodeParentProbeReply(
523
+ channelKey: Uint8Array,
524
+ reqId: number,
525
+ options: {
526
+ flags: number;
527
+ level: number;
528
+ maxChildren: number;
529
+ freeSlots: number;
530
+ children: number;
531
+ haveToExclusive: number;
532
+ missingSeqs: number;
533
+ dataWriteDrops: number;
534
+ droppedForwards: number;
535
+ reservationToken?: number;
536
+ },
537
+ ): Uint8Array;
538
+ encodeProviderAnnounce(
539
+ namespaceKey: Uint8Array,
540
+ ttlMs: number,
541
+ addrs: { bytes: Uint8Array }[],
542
+ ): Uint8Array;
543
+ encodeProviderQuery(
544
+ namespaceKey: Uint8Array,
545
+ reqId: number,
546
+ want: number,
547
+ seed: number,
548
+ ): Uint8Array;
549
+ encodeProviderReply(
550
+ namespaceKey: Uint8Array,
551
+ reqId: number,
552
+ entries: { hash: string; addrs: Uint8Array[] }[],
553
+ ): Uint8Array;
554
+ encodeProviderSubscribe(
555
+ namespaceKey: Uint8Array,
556
+ want: number,
557
+ ttlMs: number,
558
+ ): Uint8Array;
559
+ encodeProviderUnsubscribe(namespaceKey: Uint8Array): Uint8Array;
560
+ encodeProviderNotify(
561
+ namespaceKey: Uint8Array,
562
+ entries: { hash: string; addrs: Uint8Array[] }[],
563
+ ): Uint8Array;
564
+
565
+ decodeJoinReq(data: Uint8Array): RustDecodedFanoutJoinReq | undefined;
566
+ /** The shared JOIN_ACCEPT/JOIN_REJECT head (reqId) parsed before the
567
+ * pending-join lookup. */
568
+ decodeJoinResponseReqId(data: Uint8Array): number | undefined;
569
+ decodeJoinAccept(data: Uint8Array): RustDecodedFanoutJoinAccept | undefined;
570
+ decodeJoinReject(data: Uint8Array): RustDecodedFanoutJoinReject | undefined;
571
+ decodeEnd(data: Uint8Array): number | undefined;
572
+ /** MSG_REPAIR_REQ / MSG_FETCH_REQ sequence list. */
573
+ decodeRepairSeqs(data: Uint8Array): number[] | undefined;
574
+ decodeIHave(
575
+ data: Uint8Array,
576
+ ): { haveFrom: number; haveToExclusive: number } | undefined;
577
+ decodeUnicast(data: Uint8Array): RustDecodedFanoutUnicast | undefined;
578
+ decodeUnicastAck(
579
+ data: Uint8Array,
580
+ ): { ackToken: bigint; route: string[] } | undefined;
581
+ decodeRouteQuery(
582
+ data: Uint8Array,
583
+ ): { reqId: number; targetHash?: string } | undefined;
584
+ decodeRouteReply(
585
+ data: Uint8Array,
586
+ ): { reqId: number; route: string[] } | undefined;
587
+ decodeTrackerAnnounce(data: Uint8Array):
588
+ | {
589
+ ttlMs: number;
590
+ level: number;
591
+ freeSlots: number;
592
+ bidPerByte: number;
593
+ addrs: Uint8Array[];
594
+ }
595
+ | undefined;
596
+ decodeTrackerQuery(
597
+ data: Uint8Array,
598
+ ): { reqId: number; want: number } | undefined;
599
+ decodeTrackerReply(
600
+ data: Uint8Array,
601
+ ):
602
+ | { reqId: number; entries: RustDecodedFanoutTrackerReplyEntry[] }
603
+ | undefined;
604
+ decodeTrackerFeedback(
605
+ data: Uint8Array,
606
+ ): { candidateHash: string; event: number; reason: number } | undefined;
607
+ decodeParentProbeReq(data: Uint8Array):
608
+ | {
609
+ reqId: number;
610
+ minFreeSlots: number;
611
+ reserveRootCapacity: boolean;
612
+ }
613
+ | undefined;
614
+ decodeParentProbeReply(
615
+ data: Uint8Array,
616
+ hash: string,
617
+ ): RustDecodedFanoutParentProbeReply | undefined;
618
+ decodeProviderAnnounce(
619
+ data: Uint8Array,
620
+ ): { ttlMs: number; addrs: Uint8Array[] } | undefined;
621
+ decodeProviderQuery(
622
+ data: Uint8Array,
623
+ ): { reqId: number; want: number; seed: number } | undefined;
624
+ decodeProviderReply(
625
+ data: Uint8Array,
626
+ ):
627
+ | { reqId: number; entries: RustDecodedFanoutProviderEntry[] }
628
+ | undefined;
629
+ decodeProviderNotify(
630
+ data: Uint8Array,
631
+ ): { entries: RustDecodedFanoutProviderEntry[] } | undefined;
632
+ decodeProviderSubscribe(
633
+ data: Uint8Array,
634
+ ): { want: number; ttlMs: number } | undefined;
635
+
636
+ /** `normalizeParentUpgradePolicy` (PR #911). */
637
+ normalizeParentUpgradePolicy(
638
+ options: RustParentUpgradeOptions,
639
+ ): RustParentUpgradePolicy;
640
+ /**
641
+ * `evaluateParentUpgradeGate` (PR #911); applies the retry-after-seq
642
+ * reset to `state` in place, like the TS implementation.
643
+ */
644
+ evaluateParentUpgradeGate(
645
+ state: RustParentUpgradeGateState,
646
+ options: RustParentUpgradeGateOptions,
647
+ ):
648
+ | { run: true }
649
+ | {
650
+ run: false;
651
+ reason: "leaf" | "repair" | "data" | "cooldown" | "quiet" | "budget";
652
+ };
653
+ }
654
+
655
+ /**
656
+ * The full native DirectStream core: created by
657
+ * `@peerbit/network-rust`'s `createRustCoreStream()` and passed as
658
+ * `DirectStreamOptions.rustCore`.
659
+ */
660
+ export interface RustCoreStream {
661
+ /** Batched inbound decode + signature verification (implies nativeWire). */
662
+ nativeWire?: NativeWire;
663
+ createRoutes(init: RustRoutesInit): RoutesLike;
664
+ createSeenCache(init: { max: number; ttl: number }): RustSeenCache;
665
+ createLanes(init: RustLanesInit): PushableLanes<Uint8Array | Uint8ArrayList>;
666
+ decisions: RustStreamDecisions;
667
+ /** Native block-exchange components consumed by `@peerbit/blocks`. */
668
+ blockExchange?: RustBlockExchange;
669
+ /** Native topic-control-plane components consumed by `@peerbit/pubsub`. */
670
+ topicControl?: RustTopicControl;
671
+ /** Native fanout-tree components consumed by `@peerbit/pubsub`. */
672
+ fanout?: RustFanoutTree;
673
+ }
674
+
675
+ /**
676
+ * Test-only injection point: when the `PEERBIT_STREAM_RUST_CORE` env flag is
677
+ * set, DirectStream instances constructed without an explicit `rustCore`
678
+ * option pick up the core installed on globalThis under this key. This lets
679
+ * the full @peerbit/stream test-suite run unmodified against the native core
680
+ * (`rustCore: false` opts a specific instance out).
681
+ */
682
+ export const RUST_CORE_GLOBAL_KEY = "__peerbitStreamRustCore";
683
+
684
+ export const resolveInjectedRustCore = (): RustCoreStream | undefined => {
685
+ const processLike = (
686
+ globalThis as {
687
+ process?: { env?: Record<string, string | undefined> };
688
+ }
689
+ ).process;
690
+ if (!processLike?.env?.PEERBIT_STREAM_RUST_CORE) {
691
+ return undefined;
692
+ }
693
+ return (globalThis as Record<string, unknown>)[RUST_CORE_GLOBAL_KEY] as
694
+ | RustCoreStream
695
+ | undefined;
696
+ };