p2p-fret 0.4.0 → 0.5.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.
@@ -117,6 +117,13 @@ export { seedDiscovery } from './service/discovery.js';
117
117
  export { FretPeerDiscovery, type FretPeerDiscoveryConfig } from './service/peer-discovery.js';
118
118
  export { Libp2pFretService, fretService } from './service/libp2p-fret-service.js';
119
119
  export { hashKey, hashPeerId } from './ring/hash.js';
120
+ export type { RingCoord } from './ring/hash.js';
121
+ export { xorDistance, clockwiseDistance, minDistance, lexLess } from './ring/distance.js';
122
+ export { DigitreeStore } from './store/digitree-store.js';
123
+ export type { PeerEntry, PeerState } from './store/digitree-store.js';
124
+ export { estimateSizeAndConfidence } from './estimate/size-estimator.js';
125
+ export type { SizeEstimate } from './estimate/size-estimator.js';
126
+ export { assembleCohort } from './service/cohort.js';
120
127
  export { shouldIncludePayload, computeNearRadius } from './service/payload-heuristic.js';
121
128
  export { DedupCache } from './service/dedup-cache.js';
122
129
  export { validateTimestamp, readAllBounded } from './rpc/protocols.js';
package/dist/src/index.js CHANGED
@@ -4,6 +4,10 @@ export { seedDiscovery } from './service/discovery.js';
4
4
  export { FretPeerDiscovery } from './service/peer-discovery.js';
5
5
  export { Libp2pFretService, fretService } from './service/libp2p-fret-service.js';
6
6
  export { hashKey, hashPeerId } from './ring/hash.js';
7
+ export { xorDistance, clockwiseDistance, minDistance, lexLess } from './ring/distance.js';
8
+ export { DigitreeStore } from './store/digitree-store.js';
9
+ export { estimateSizeAndConfidence } from './estimate/size-estimator.js';
10
+ export { assembleCohort } from './service/cohort.js';
7
11
  export { shouldIncludePayload, computeNearRadius } from './service/payload-heuristic.js';
8
12
  export { DedupCache } from './service/dedup-cache.js';
9
13
  export { validateTimestamp, readAllBounded } from './rpc/protocols.js';
@@ -0,0 +1,11 @@
1
+ import type { DigitreeStore } from '../store/digitree-store.js';
2
+ /**
3
+ * Two-sided cohort assembly: an alternating successor/predecessor walk outward from
4
+ * `hashedCoord`, returning up to `wants` distinct peer ids. Auto-adapts when fewer than
5
+ * `wants` peers exist (`n < k`) by returning whatever the ring holds.
6
+ *
7
+ * Pure over the store — no libp2p/node state — so the same selection logic is shared by
8
+ * `FretService.assembleCohort` and out-of-band consumers (e.g. the Optimystic design
9
+ * simulator) with zero divergence.
10
+ */
11
+ export declare function assembleCohort(store: DigitreeStore, hashedCoord: Uint8Array, wants: number, exclude?: Set<string>): string[];
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Two-sided cohort assembly: an alternating successor/predecessor walk outward from
3
+ * `hashedCoord`, returning up to `wants` distinct peer ids. Auto-adapts when fewer than
4
+ * `wants` peers exist (`n < k`) by returning whatever the ring holds.
5
+ *
6
+ * Pure over the store — no libp2p/node state — so the same selection logic is shared by
7
+ * `FretService.assembleCohort` and out-of-band consumers (e.g. the Optimystic design
8
+ * simulator) with zero divergence.
9
+ */
10
+ export function assembleCohort(store, hashedCoord, wants, exclude) {
11
+ const out = [];
12
+ const ex = exclude ?? new Set();
13
+ const succIds = store.neighborsRight(hashedCoord, wants * 2);
14
+ const predIds = store.neighborsLeft(hashedCoord, wants * 2);
15
+ let si = 0, pi = 0;
16
+ while (out.length < wants && (si < succIds.length || pi < predIds.length)) {
17
+ if (out.length % 2 === 0 && si < succIds.length) {
18
+ const id = succIds[si++];
19
+ if (id && !ex.has(id))
20
+ out.push(id);
21
+ }
22
+ else if (pi < predIds.length) {
23
+ const id = predIds[pi++];
24
+ if (id && !ex.has(id))
25
+ out.push(id);
26
+ }
27
+ else if (si < succIds.length) {
28
+ const id = succIds[si++];
29
+ if (id && !ex.has(id))
30
+ out.push(id);
31
+ }
32
+ }
33
+ return Array.from(new Set(out)).slice(0, wants);
34
+ }
@@ -14,6 +14,7 @@ import { chooseNextHop } from '../selector/next-hop.js';
14
14
  import { DedupCache } from './dedup-cache.js';
15
15
  import { shouldIncludePayload, computeNearRadius } from './payload-heuristic.js';
16
16
  import { xorDistance } from '../ring/distance.js';
17
+ import { assembleCohort as assembleCohortOverStore } from './cohort.js';
17
18
  import { createSparsityModel, normalizedLogDistance, sparsityBonus, touch as scoreTouch, recordSuccess as scoreSuccess, recordFailure as scoreFailure, } from '../store/relevance.js';
18
19
  import { createLogger } from '../logger.js';
19
20
  const log = createLogger('service:fret');
@@ -908,29 +909,7 @@ export class FretService {
908
909
  return arr[(idx - 1 + arr.length) % arr.length];
909
910
  }
910
911
  assembleCohort(hashedCoord, wants, exclude) {
911
- const out = [];
912
- const ex = exclude ?? new Set();
913
- const succIds = this.store.neighborsRight(hashedCoord, wants * 2);
914
- const predIds = this.store.neighborsLeft(hashedCoord, wants * 2);
915
- let si = 0, pi = 0;
916
- while (out.length < wants && (si < succIds.length || pi < predIds.length)) {
917
- if (out.length % 2 === 0 && si < succIds.length) {
918
- const id = succIds[si++];
919
- if (id && !ex.has(id))
920
- out.push(id);
921
- }
922
- else if (pi < predIds.length) {
923
- const id = predIds[pi++];
924
- if (id && !ex.has(id))
925
- out.push(id);
926
- }
927
- else if (si < succIds.length) {
928
- const id = succIds[si++];
929
- if (id && !ex.has(id))
930
- out.push(id);
931
- }
932
- }
933
- return Array.from(new Set(out)).slice(0, wants);
912
+ return assembleCohortOverStore(this.store, hashedCoord, wants, exclude);
934
913
  }
935
914
  expandCohort(current, hashedCoord, step, exclude) {
936
915
  const base = new Set(current);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "p2p-fret",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "FRET: Finger Ring Ensemble Topology (libp2p ring overlay with Digitree)",
6
6
  "main": "dist/src/index.js",
@@ -20,7 +20,7 @@
20
20
  "scripts": {
21
21
  "clean": "rimraf dist",
22
22
  "build": "tsc",
23
- "test": "node --import ./register.mjs node_modules/mocha/bin/mocha.js \"test/**/*.spec.ts\" --colors"
23
+ "test": "node --import ./register.mjs node_modules/mocha/bin/mocha.js \"test/**/*.spec.ts\" --colors --exit"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "@libp2p/interface": "^3.1.0",
package/src/index.ts CHANGED
@@ -126,6 +126,13 @@ export { seedDiscovery } from './service/discovery.js';
126
126
  export { FretPeerDiscovery, type FretPeerDiscoveryConfig } from './service/peer-discovery.js';
127
127
  export { Libp2pFretService, fretService } from './service/libp2p-fret-service.js';
128
128
  export { hashKey, hashPeerId } from './ring/hash.js';
129
+ export type { RingCoord } from './ring/hash.js';
130
+ export { xorDistance, clockwiseDistance, minDistance, lexLess } from './ring/distance.js';
131
+ export { DigitreeStore } from './store/digitree-store.js';
132
+ export type { PeerEntry, PeerState } from './store/digitree-store.js';
133
+ export { estimateSizeAndConfidence } from './estimate/size-estimator.js';
134
+ export type { SizeEstimate } from './estimate/size-estimator.js';
135
+ export { assembleCohort } from './service/cohort.js';
129
136
  export { shouldIncludePayload, computeNearRadius } from './service/payload-heuristic.js';
130
137
  export { DedupCache } from './service/dedup-cache.js';
131
138
  export { validateTimestamp, readAllBounded } from './rpc/protocols.js';
@@ -0,0 +1,37 @@
1
+ import type { DigitreeStore } from '../store/digitree-store.js';
2
+
3
+ /**
4
+ * Two-sided cohort assembly: an alternating successor/predecessor walk outward from
5
+ * `hashedCoord`, returning up to `wants` distinct peer ids. Auto-adapts when fewer than
6
+ * `wants` peers exist (`n < k`) by returning whatever the ring holds.
7
+ *
8
+ * Pure over the store — no libp2p/node state — so the same selection logic is shared by
9
+ * `FretService.assembleCohort` and out-of-band consumers (e.g. the Optimystic design
10
+ * simulator) with zero divergence.
11
+ */
12
+ export function assembleCohort(
13
+ store: DigitreeStore,
14
+ hashedCoord: Uint8Array,
15
+ wants: number,
16
+ exclude?: Set<string>
17
+ ): string[] {
18
+ const out: string[] = [];
19
+ const ex = exclude ?? new Set<string>();
20
+ const succIds = store.neighborsRight(hashedCoord, wants * 2);
21
+ const predIds = store.neighborsLeft(hashedCoord, wants * 2);
22
+ let si = 0,
23
+ pi = 0;
24
+ while (out.length < wants && (si < succIds.length || pi < predIds.length)) {
25
+ if (out.length % 2 === 0 && si < succIds.length) {
26
+ const id = succIds[si++];
27
+ if (id && !ex.has(id)) out.push(id);
28
+ } else if (pi < predIds.length) {
29
+ const id = predIds[pi++];
30
+ if (id && !ex.has(id)) out.push(id);
31
+ } else if (si < succIds.length) {
32
+ const id = succIds[si++];
33
+ if (id && !ex.has(id)) out.push(id);
34
+ }
35
+ }
36
+ return Array.from(new Set(out)).slice(0, wants);
37
+ }
@@ -30,6 +30,7 @@ import { chooseNextHop, type NextHopOptions } from '../selector/next-hop.js';
30
30
  import { DedupCache } from './dedup-cache.js';
31
31
  import { shouldIncludePayload, computeNearRadius } from './payload-heuristic.js';
32
32
  import { xorDistance } from '../ring/distance.js';
33
+ import { assembleCohort as assembleCohortOverStore } from './cohort.js';
33
34
  import {
34
35
  createSparsityModel,
35
36
  normalizedLogDistance,
@@ -881,25 +882,7 @@ export class FretService implements IFretService, Startable {
881
882
  }
882
883
 
883
884
  assembleCohort(hashedCoord: Uint8Array, wants: number, exclude?: Set<string>): string[] {
884
- const out: string[] = [];
885
- const ex = exclude ?? new Set<string>();
886
- const succIds = this.store.neighborsRight(hashedCoord, wants * 2);
887
- const predIds = this.store.neighborsLeft(hashedCoord, wants * 2);
888
- let si = 0,
889
- pi = 0;
890
- while (out.length < wants && (si < succIds.length || pi < predIds.length)) {
891
- if (out.length % 2 === 0 && si < succIds.length) {
892
- const id = succIds[si++];
893
- if (id && !ex.has(id)) out.push(id);
894
- } else if (pi < predIds.length) {
895
- const id = predIds[pi++];
896
- if (id && !ex.has(id)) out.push(id);
897
- } else if (si < succIds.length) {
898
- const id = succIds[si++];
899
- if (id && !ex.has(id)) out.push(id);
900
- }
901
- }
902
- return Array.from(new Set(out)).slice(0, wants);
885
+ return assembleCohortOverStore(this.store, hashedCoord, wants, exclude);
903
886
  }
904
887
 
905
888
  expandCohort(