@peerbit/shared-log 13.0.5 → 13.0.6-cba1bcc

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peerbit/shared-log",
3
- "version": "13.0.5",
3
+ "version": "13.0.6-cba1bcc",
4
4
  "description": "Shared log",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -54,35 +54,35 @@
54
54
  "dependencies": {
55
55
  "@dao-xyz/borsh": "^6.0.0",
56
56
  "@libp2p/crypto": "^5.1.10",
57
+ "@peerbit/log": "6.0.5-cba1bcc",
58
+ "@peerbit/logger": "2.0.0-cba1bcc",
59
+ "@peerbit/program": "6.0.3-cba1bcc",
60
+ "@peerbit/riblt": "1.2.0-cba1bcc",
61
+ "@peerbit/rpc": "6.0.5-cba1bcc",
62
+ "@peerbit/any-store": "2.2.5-cba1bcc",
63
+ "@peerbit/blocks": "4.0.2-cba1bcc",
64
+ "@peerbit/blocks-interface": "2.0.1-cba1bcc",
65
+ "@peerbit/cache": "3.0.0-cba1bcc",
66
+ "@peerbit/crypto": "3.0.0-cba1bcc",
67
+ "@peerbit/indexer-interface": "3.0.0-cba1bcc",
68
+ "@peerbit/indexer-sqlite3": "3.0.0-cba1bcc",
69
+ "@peerbit/pubsub": "5.0.2-cba1bcc",
70
+ "@peerbit/pubsub-interface": "5.0.1-cba1bcc",
71
+ "@peerbit/stream-interface": "6.0.1-cba1bcc",
72
+ "@peerbit/time": "3.0.0-cba1bcc",
57
73
  "json-stringify-deterministic": "^1.0.7",
58
74
  "p-each-series": "^3.0.0",
59
75
  "p-defer": "^4.0.0",
60
76
  "p-queue": "^8.0.1",
61
77
  "pidusage": "^4.0.1",
62
78
  "pino": "^9.4.0",
63
- "uint8arrays": "^5.1.0",
64
- "@peerbit/log": "6.0.4",
65
- "@peerbit/logger": "2.0.0",
66
- "@peerbit/program": "6.0.2",
67
- "@peerbit/riblt": "1.2.0",
68
- "@peerbit/rpc": "6.0.4",
69
- "@peerbit/any-store": "2.2.5",
70
- "@peerbit/blocks": "4.0.1",
71
- "@peerbit/blocks-interface": "2.0.1",
72
- "@peerbit/cache": "3.0.0",
73
- "@peerbit/crypto": "3.0.0",
74
- "@peerbit/indexer-interface": "3.0.0",
75
- "@peerbit/indexer-sqlite3": "3.0.0",
76
- "@peerbit/pubsub": "5.0.2",
77
- "@peerbit/pubsub-interface": "5.0.1",
78
- "@peerbit/stream-interface": "6.0.1",
79
- "@peerbit/time": "3.0.0"
79
+ "uint8arrays": "^5.1.0"
80
80
  },
81
81
  "devDependencies": {
82
+ "@peerbit/test-utils": "3.0.5-cba1bcc",
82
83
  "@types/libsodium-wrappers": "^0.7.14",
83
84
  "@types/pidusage": "^2.0.5",
84
- "uuid": "^10.0.0",
85
- "@peerbit/test-utils": "3.0.4"
85
+ "uuid": "^10.0.0"
86
86
  },
87
87
  "scripts": {
88
88
  "clean": "aegir clean",
package/src/index.ts CHANGED
@@ -2887,17 +2887,14 @@ export class SharedLog<
2887
2887
  // ignore discovery failures
2888
2888
  }
2889
2889
 
2890
- // 2) fallback to currently connected RPC peers
2891
- const self = this.node.identity.publicKey.hashcode();
2892
- const out: string[] = [];
2893
- const peers = (this.rpc as any)?.peers;
2894
- for (const h of peers?.keys?.() ?? []) {
2895
- if (h === self) continue;
2896
- if (out.includes(h)) continue;
2897
- out.push(h);
2898
- if (out.length >= 32) break;
2899
- }
2900
- return out;
2890
+ // 2) reuse the same per-hash / replicator / subscriber fallback used by
2891
+ // entry loads so block retries can widen beyond stale explicit hints.
2892
+ return (
2893
+ (await this.resolveCandidatePeersForHash(cid, {
2894
+ signal: opts?.signal,
2895
+ maxPeers: 8,
2896
+ })) ?? []
2897
+ );
2901
2898
  },
2902
2899
  onPut: async (cid) => {
2903
2900
  // Best-effort directory announce for "get without remote.from" workflows.
@@ -3024,87 +3021,11 @@ export class SharedLog<
3024
3021
 
3025
3022
  await this.log.open(this.remoteBlocks, this.node.identity, {
3026
3023
  keychain: this.node.services.keychain,
3027
- resolveRemotePeers: async (hash, options) => {
3028
- if (options?.signal?.aborted) return undefined;
3029
-
3030
- const maxPeers = 8;
3031
- const self = this.node.identity.publicKey.hashcode();
3032
- const seed = hashToSeed32(hash);
3033
-
3034
- // Best hint: peers that have recently confirmed having this entry hash.
3035
- const hinted = this._requestIPruneResponseReplicatorSet.get(hash);
3036
- if (hinted && hinted.size > 0) {
3037
- const peers = [...hinted].filter((p) => p !== self);
3038
- return peers.length > 0
3039
- ? pickDeterministicSubset(peers, seed, maxPeers)
3040
- : undefined;
3041
- }
3042
-
3043
- // Next: peers we already contacted about this hash (may still have it).
3044
- const contacted = this._requestIPruneSent.get(hash);
3045
- if (contacted && contacted.size > 0) {
3046
- const peers = [...contacted].filter((p) => p !== self);
3047
- return peers.length > 0
3048
- ? pickDeterministicSubset(peers, seed, maxPeers)
3049
- : undefined;
3050
- }
3051
-
3052
- let candidates: string[] | undefined;
3053
-
3054
- // Prefer the replicator cache; fall back to subscribers if we have no other signal.
3055
- const replicatorCandidates = [...this.uniqueReplicators].filter(
3056
- (p) => p !== self,
3057
- );
3058
- if (replicatorCandidates.length > 0) {
3059
- candidates = replicatorCandidates;
3060
- } else {
3061
- try {
3062
- const subscribers = await this._getTopicSubscribers(this.topic);
3063
- const subscriberCandidates =
3064
- subscribers?.map((k) => k.hashcode()).filter((p) => p !== self) ??
3065
- [];
3066
- candidates =
3067
- subscriberCandidates.length > 0 ? subscriberCandidates : undefined;
3068
- } catch {
3069
- // Best-effort only.
3070
- }
3071
-
3072
- if (!candidates || candidates.length === 0) {
3073
- // Last resort: peers we are already directly connected to. This avoids
3074
- // depending on global membership knowledge in early-join scenarios.
3075
- const peerMap = (this.node.services.pubsub as any)?.peers;
3076
- if (peerMap?.keys) {
3077
- candidates = [...peerMap.keys()];
3078
- }
3079
- }
3080
-
3081
- if (!candidates || candidates.length === 0) {
3082
- // Even if the pubsub stream has no established peer streams yet, we may
3083
- // still have a libp2p connection to one or more peers (e.g. bootstrap).
3084
- const connectionManager = (this.node.services.pubsub as any)?.components
3085
- ?.connectionManager;
3086
- const connections = connectionManager?.getConnections?.() ?? [];
3087
- const connectionHashes: string[] = [];
3088
- for (const conn of connections) {
3089
- const peerId = conn?.remotePeer;
3090
- if (!peerId) continue;
3091
- try {
3092
- connectionHashes.push(getPublicKeyFromPeerId(peerId).hashcode());
3093
- } catch {
3094
- // Best-effort only.
3095
- }
3096
- }
3097
- if (connectionHashes.length > 0) {
3098
- candidates = connectionHashes;
3099
- }
3100
- }
3101
- }
3102
-
3103
- if (!candidates || candidates.length === 0) return undefined;
3104
- const peers = candidates.filter((p) => p !== self);
3105
- if (peers.length === 0) return undefined;
3106
- return pickDeterministicSubset(peers, seed, maxPeers);
3107
- },
3024
+ resolveRemotePeers: (hash, options) =>
3025
+ this.resolveCandidatePeersForHash(hash, {
3026
+ signal: options?.signal,
3027
+ maxPeers: 8,
3028
+ }),
3108
3029
  ...this._logProperties,
3109
3030
  onChange: async (change) => {
3110
3031
  await this.onChange(change);
@@ -3492,6 +3413,80 @@ export class SharedLog<
3492
3413
  this._replicatorLivenessTargetsSize = -1;
3493
3414
  }
3494
3415
 
3416
+ private async resolveCandidatePeersForHash(
3417
+ hash: string,
3418
+ options?: { signal?: AbortSignal; maxPeers?: number },
3419
+ ): Promise<string[] | undefined> {
3420
+ if (options?.signal?.aborted) return undefined;
3421
+
3422
+ const maxPeers = options?.maxPeers ?? 8;
3423
+ const self = this.node.identity.publicKey.hashcode();
3424
+ const seed = hashToSeed32(hash);
3425
+
3426
+ const hinted = this._requestIPruneResponseReplicatorSet.get(hash);
3427
+ if (hinted && hinted.size > 0) {
3428
+ const peers = [...hinted].filter((p) => p !== self);
3429
+ return peers.length > 0
3430
+ ? pickDeterministicSubset(peers, seed, maxPeers)
3431
+ : undefined;
3432
+ }
3433
+
3434
+ const contacted = this._requestIPruneSent.get(hash);
3435
+ if (contacted && contacted.size > 0) {
3436
+ const peers = [...contacted].filter((p) => p !== self);
3437
+ return peers.length > 0
3438
+ ? pickDeterministicSubset(peers, seed, maxPeers)
3439
+ : undefined;
3440
+ }
3441
+
3442
+ let candidates: string[] | undefined;
3443
+ const replicatorCandidates = [...this.uniqueReplicators].filter((p) => p !== self);
3444
+ if (replicatorCandidates.length > 0) {
3445
+ candidates = replicatorCandidates;
3446
+ } else {
3447
+ try {
3448
+ const subscribers = await this._getTopicSubscribers(this.topic);
3449
+ const subscriberCandidates =
3450
+ subscribers?.map((k) => k.hashcode()).filter((p) => p !== self) ?? [];
3451
+ candidates =
3452
+ subscriberCandidates.length > 0 ? subscriberCandidates : undefined;
3453
+ } catch {
3454
+ // Best-effort only.
3455
+ }
3456
+
3457
+ if (!candidates || candidates.length === 0) {
3458
+ const peerMap = (this.node.services.pubsub as any)?.peers;
3459
+ if (peerMap?.keys) {
3460
+ candidates = [...peerMap.keys()];
3461
+ }
3462
+ }
3463
+
3464
+ if (!candidates || candidates.length === 0) {
3465
+ const connectionManager = (this.node.services.pubsub as any)?.components
3466
+ ?.connectionManager;
3467
+ const connections = connectionManager?.getConnections?.() ?? [];
3468
+ const connectionHashes: string[] = [];
3469
+ for (const conn of connections) {
3470
+ const peerId = conn?.remotePeer;
3471
+ if (!peerId) continue;
3472
+ try {
3473
+ connectionHashes.push(getPublicKeyFromPeerId(peerId).hashcode());
3474
+ } catch {
3475
+ // Best-effort only.
3476
+ }
3477
+ }
3478
+ if (connectionHashes.length > 0) {
3479
+ candidates = connectionHashes;
3480
+ }
3481
+ }
3482
+ }
3483
+
3484
+ if (!candidates || candidates.length === 0) return undefined;
3485
+ const peers = candidates.filter((p) => p !== self);
3486
+ if (peers.length === 0) return undefined;
3487
+ return pickDeterministicSubset(peers, seed, maxPeers);
3488
+ }
3489
+
3495
3490
  private async runReplicatorLivenessSweep() {
3496
3491
  if (this.closed || this._closeController.signal.aborted) {
3497
3492
  return;