Skip to content

Commit a2c0467

Browse files
authored
chore: improve types for Hypercore peers (#735)
*This is a types-only change.* Before this change, we used `any` for a Hypercore peer's type. After this change, we use a new type, `HypercorePeer`, designed to match [Hypercore's `Peer` class][0]. Ideally, we would put this in `@digidem/types` or DefinitelyTyped. For now, I think this is an improvement over the `any`s we currently use. I did this because I'm working with peer-related code and found the `any`s difficult to work with. [0]: https://github.com/holepunchto/hypercore/blob/de993dc051301f03570df0eb7929c06286745563/lib/replicator.js#L331
1 parent b243235 commit a2c0467

3 files changed

Lines changed: 40 additions & 11 deletions

File tree

src/core-manager/index.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { coresTable } from '../schema/project.js'
1414
import * as rle from './bitfield-rle.js'
1515
import { CoreIndex } from './core-index.js'
1616

17+
/** @typedef {import('../types.js').HypercorePeer} HypercorePeer */
18+
1719
const WRITER_CORE_PREHAVES_DEBOUNCE_DELAY = 1000
1820

1921
export const kCoreManagerReplicate = Symbol('replicate core manager')
@@ -401,7 +403,7 @@ export class CoreManager extends TypedEmitter {
401403

402404
/**
403405
* @param {ProjectExtension} msg
404-
* @param {any} peer
406+
* @param {HypercorePeer} peer
405407
*/
406408
#handleProjectMessage({ wantCoreKeys, ...coreKeys }, peer) {
407409
const message = ProjectExtension.create()
@@ -426,7 +428,7 @@ export class CoreManager extends TypedEmitter {
426428

427429
/**
428430
* @param {Omit<HaveMsg, 'namespace'> & { namespace: Namespace | 'UNRECOGNIZED' }} msg
429-
* @param {any} peer
431+
* @param {HypercorePeer} peer
430432
*/
431433
#handleHaveMessage(msg, peer) {
432434
const { start, discoveryKey, bitfield, namespace } = msg
@@ -444,7 +446,7 @@ export class CoreManager extends TypedEmitter {
444446

445447
/**
446448
*
447-
* @param {any} peer
449+
* @param {HypercorePeer} peer
448450
* @param {Iterable<{ core: Hypercore<Hypercore.ValueEncoding, Buffer>, namespace: Namespace }>} cores
449451
*/
450452
async #sendHaves(peer, cores) {
@@ -639,7 +641,7 @@ function findPeer(core, publicKey, { timeout = 200 } = {}) {
639641

640642
core.on('peer-add', onPeer)
641643

642-
/** @param {any} peer */
644+
/** @param {HypercorePeer} peer */
643645
function onPeer(peer) {
644646
if (peer.remotePublicKey.equals(publicKey)) {
645647
clearTimeout(timeoutId)

src/sync/core-sync-state.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { keyToId } from '../utils.js'
22
import RemoteBitfield, {
33
BITS_PER_PAGE,
44
} from '../core-manager/remote-bitfield.js'
5+
/** @typedef {import('../types.js').HypercoreRemoteBitfield} HypercoreRemoteBitfield */
6+
/** @typedef {import('../types.js').HypercorePeer} HypercorePeer */
57

68
/**
79
* @typedef {RemoteBitfield} Bitfield
@@ -192,7 +194,7 @@ export class CoreSyncState {
192194
* emit state updates whenever the peer remote bitfield changes
193195
*
194196
* (defined as class field to bind to `this`)
195-
* @param {any} peer
197+
* @param {HypercorePeer} peer
196198
*/
197199
#onPeerAdd = (peer) => {
198200
const peerId = keyToId(peer.remotePublicKey)
@@ -217,11 +219,11 @@ export class CoreSyncState {
217219
// a result of these two internal calls.
218220
const originalOnBitfield = peer.onbitfield
219221
const originalOnRange = peer.onrange
220-
peer.onbitfield = (/** @type {any[]} */ ...args) => {
222+
peer.onbitfield = (...args) => {
221223
originalOnBitfield.apply(peer, args)
222224
this.#update()
223225
}
224-
peer.onrange = (/** @type {any[]} */ ...args) => {
226+
peer.onrange = (...args) => {
225227
originalOnRange.apply(peer, args)
226228
this.#update()
227229
}
@@ -231,7 +233,7 @@ export class CoreSyncState {
231233
* Handle a peer being removed - keeps it in state, but sets state.connected = false
232234
*
233235
* (defined as class field to bind to `this`)
234-
* @param {any} peer
236+
* @param {HypercorePeer} peer
235237
*/
236238
#onPeerRemove = (peer) => {
237239
const peerId = keyToId(peer.remotePublicKey)
@@ -253,7 +255,7 @@ export class CoreSyncState {
253255
export class PeerState {
254256
/** @type {Bitfield} */
255257
#preHaves = new RemoteBitfield()
256-
/** @type {Bitfield | undefined} */
258+
/** @type {HypercoreRemoteBitfield | undefined} */
257259
#haves
258260
/** @type {Bitfield} */
259261
#wants = new RemoteBitfield()
@@ -274,7 +276,7 @@ export class PeerState {
274276
return this.#preHaves.insert(start, bitfield)
275277
}
276278
/**
277-
* @param {Bitfield} bitfield
279+
* @param {HypercoreRemoteBitfield} bitfield
278280
*/
279281
setHavesBitfield(bitfield) {
280282
this.#haves = bitfield
@@ -434,7 +436,7 @@ export function bitCount32(n) {
434436
/**
435437
* Get a 32-bit "chunk" (word) of the bitfield.
436438
*
437-
* @param {RemoteBitfield} bitfield
439+
* @param {Bitfield | HypercoreRemoteBitfield} bitfield
438440
* @param {number} index
439441
*/
440442
function getBitfieldWord(bitfield, index) {

src/types.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
} from 'type-fest'
88
import { SUPPORTED_BLOB_VARIANTS } from './blob-store/index.js'
99
import { MapeoCommon, MapeoDoc, MapeoValue, decode } from '@mapeo/schema'
10+
import type BigSparseArray from 'big-sparse-array'
1011
import type Protomux from 'protomux'
1112
import type NoiseStream from '@hyperswarm/secret-stream'
1213
import { Duplex } from 'streamx'
@@ -105,6 +106,30 @@ export type PublicKey = Buffer
105106
export type SecretKey = Buffer
106107
export type IdentityKeyPair = KeyPair
107108

109+
type HypercoreRemoteBitfieldPage = {
110+
bitfield: Uint32Array
111+
}
112+
113+
/**
114+
* A subset of Hypercore's `RemoteBitfield` class that we use.
115+
*/
116+
export type HypercoreRemoteBitfield = {
117+
_pages: BigSparseArray<HypercoreRemoteBitfieldPage>
118+
get(index: number): boolean
119+
}
120+
121+
/**
122+
* A subset of Hypercore's `Peer` class that we use.
123+
* TODO: Contribute these types upstream.
124+
*/
125+
export type HypercorePeer = {
126+
protomux: Protomux
127+
remotePublicKey: Buffer
128+
remoteBitfield: HypercoreRemoteBitfield
129+
onbitfield: (options: { start: number; bitfield: Buffer }) => void
130+
onrange: (options: { drop: boolean; start: number; length: number }) => void
131+
}
132+
108133
export { NoiseStream }
109134
type ProtocolStream = Omit<NoiseStream, 'userData'> & {
110135
userData: Protomux

0 commit comments

Comments
 (0)