diff --git a/packages/interface/src/connection-gater/index.ts b/packages/interface/src/connection-gater/index.ts index 1b59de4f38..fe618d7c88 100644 --- a/packages/interface/src/connection-gater/index.ts +++ b/packages/interface/src/connection-gater/index.ts @@ -12,7 +12,7 @@ export interface ConnectionGater { * * Return true to prevent dialing the passed peer. */ - denyDialPeer?(peerId: PeerId): Promise + denyDialPeer?(peerId: PeerId): Promise | boolean /** * denyDialMultiaddr tests whether we're permitted to dial the specified @@ -23,7 +23,7 @@ export interface ConnectionGater { * * Return true to prevent dialing the passed peer on the passed multiaddr. */ - denyDialMultiaddr?(multiaddr: Multiaddr): Promise + denyDialMultiaddr?(multiaddr: Multiaddr): Promise | boolean /** * denyInboundConnection tests whether an incipient inbound connection is allowed. @@ -33,7 +33,7 @@ export interface ConnectionGater { * * Return true to deny the incoming passed connection. */ - denyInboundConnection?(maConn: MultiaddrConnection): Promise + denyInboundConnection?(maConn: MultiaddrConnection): Promise | boolean /** * denyOutboundConnection tests whether an incipient outbound connection is allowed. @@ -43,7 +43,7 @@ export interface ConnectionGater { * * Return true to deny the incoming passed connection. */ - denyOutboundConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise + denyOutboundConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise | boolean /** * denyInboundEncryptedConnection tests whether a given connection, now encrypted, @@ -55,7 +55,7 @@ export interface ConnectionGater { * * Return true to deny the passed secured connection. */ - denyInboundEncryptedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise + denyInboundEncryptedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise | boolean /** * denyOutboundEncryptedConnection tests whether a given connection, now encrypted, @@ -67,7 +67,7 @@ export interface ConnectionGater { * * Return true to deny the passed secured connection. */ - denyOutboundEncryptedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise + denyOutboundEncryptedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise | boolean /** * denyInboundUpgradedConnection tests whether a fully capable connection is allowed. @@ -77,7 +77,7 @@ export interface ConnectionGater { * * Return true to deny the passed upgraded connection. */ - denyInboundUpgradedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise + denyInboundUpgradedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise | boolean /** * denyOutboundUpgradedConnection tests whether a fully capable connection is allowed. @@ -87,7 +87,7 @@ export interface ConnectionGater { * * Return true to deny the passed upgraded connection. */ - denyOutboundUpgradedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise + denyOutboundUpgradedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise | boolean /** * denyInboundRelayReservation tests whether a remote peer is allowed make a @@ -95,7 +95,7 @@ export interface ConnectionGater { * * Return true to deny the relay reservation. */ - denyInboundRelayReservation?(source: PeerId): Promise + denyInboundRelayReservation?(source: PeerId): Promise | boolean /** * denyOutboundRelayedConnection tests whether a remote peer is allowed to open a relayed @@ -106,7 +106,7 @@ export interface ConnectionGater { * * Return true to deny the relayed connection. */ - denyOutboundRelayedConnection?(source: PeerId, destination: PeerId): Promise + denyOutboundRelayedConnection?(source: PeerId, destination: PeerId): Promise | boolean /** * denyInboundRelayedConnection tests whether a remote peer is allowed to open a relayed @@ -117,12 +117,12 @@ export interface ConnectionGater { * * Return true to deny the relayed connection. */ - denyInboundRelayedConnection?(relay: PeerId, remotePeer: PeerId): Promise + denyInboundRelayedConnection?(relay: PeerId, remotePeer: PeerId): Promise | boolean /** * Used by the address book to filter passed addresses. * * Return true to allow storing the passed multiaddr for the passed peer. */ - filterMultiaddrForPeer?(peer: PeerId, multiaddr: Multiaddr): Promise + filterMultiaddrForPeer?(peer: PeerId, multiaddr: Multiaddr): Promise | boolean } diff --git a/packages/interface/src/index.ts b/packages/interface/src/index.ts index eb1022925b..47b1402908 100644 --- a/packages/interface/src/index.ts +++ b/packages/interface/src/index.ts @@ -684,15 +684,6 @@ export interface LoggerOptions { log: Logger } -/** - * Returns a new type with all fields marked optional. - * - * Borrowed from the tsdef module. - */ -export type RecursivePartial = { - [P in keyof T]?: T[P] extends Array ? Array> : T[P] extends (...args: any[]) => any ? T[P] : RecursivePartial -} - /** * When a routing operation involves reading values, these options allow * controlling where the values are read from. By default libp2p will check diff --git a/packages/libp2p/src/config.ts b/packages/libp2p/src/config.ts index 568f1bd985..606e4efa53 100644 --- a/packages/libp2p/src/config.ts +++ b/packages/libp2p/src/config.ts @@ -5,10 +5,10 @@ import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers' import mergeOptions from 'merge-options' import { codes, messages } from './errors.js' import type { Libp2pInit } from './index.js' -import type { ServiceMap, RecursivePartial } from '@libp2p/interface' +import type { ServiceMap } from '@libp2p/interface' import type { Multiaddr } from '@multiformats/multiaddr' -const DefaultConfig: Partial = { +const DefaultConfig: Libp2pInit = { addresses: { listen: [], announce: [], @@ -26,14 +26,14 @@ const DefaultConfig: Partial = { } } -export async function validateConfig > (opts: RecursivePartial>): Promise> { - const resultingOptions: Libp2pInit = mergeOptions(DefaultConfig, opts) +export async function validateConfig > (opts: Libp2pInit): Promise & Required, 'peerId'>>> { + const resultingOptions: Libp2pInit & Required, 'peerId'>> = mergeOptions(DefaultConfig, opts) if (resultingOptions.connectionProtector === null && globalThis.process?.env?.LIBP2P_FORCE_PNET != null) { // eslint-disable-line no-undef throw new CodeError(messages.ERR_PROTECTOR_REQUIRED, codes.ERR_PROTECTOR_REQUIRED) } - if (!(await peerIdFromKeys(resultingOptions.privateKey.public.bytes, resultingOptions.privateKey.bytes)).equals(resultingOptions.peerId)) { + if (resultingOptions.privateKey != null && !(await peerIdFromKeys(resultingOptions.privateKey.public.bytes, resultingOptions.privateKey.bytes)).equals(resultingOptions.peerId)) { throw new CodeError('Private key doesn\'t match peer id', codes.ERR_INVALID_KEY) } diff --git a/packages/libp2p/src/index.ts b/packages/libp2p/src/index.ts index 82542aa6f7..a123bd9e2b 100644 --- a/packages/libp2p/src/index.ts +++ b/packages/libp2p/src/index.ts @@ -19,13 +19,13 @@ import type { AddressManagerInit } from './address-manager/index.js' import type { Components } from './components.js' import type { ConnectionManagerInit } from './connection-manager/index.js' import type { TransportManagerInit } from './transport-manager.js' -import type { Libp2p, ServiceMap, RecursivePartial, ComponentLogger, NodeInfo, ConnectionProtector, ConnectionEncrypter, ConnectionGater, ContentRouting, Metrics, PeerDiscovery, PeerId, PeerRouting, StreamMuxerFactory, Transport, PrivateKey } from '@libp2p/interface' +import type { Libp2p, ServiceMap, ComponentLogger, NodeInfo, ConnectionProtector, ConnectionEncrypter, ConnectionGater, ContentRouting, Metrics, PeerDiscovery, PeerId, PeerRouting, StreamMuxerFactory, Transport, PrivateKey } from '@libp2p/interface' import type { PersistentPeerStoreInit } from '@libp2p/peer-store' import type { DNS } from '@multiformats/dns' import type { Datastore } from 'interface-datastore' export type ServiceFactoryMap = Record> = { - [Property in keyof T]: (components: Components) => T[Property] + [Property in keyof T]: (components: Components & T) => T[Property] } /** @@ -35,49 +35,49 @@ export interface Libp2pInit /** * peerId instance (it will be created if not provided) */ - peerId: PeerId + peerId?: PeerId /** * Private key associated with the peerId */ - privateKey: PrivateKey + privateKey?: PrivateKey /** * Metadata about the node - implementation name, version number, etc */ - nodeInfo: NodeInfo + nodeInfo?: NodeInfo /** * Addresses for transport listening and to advertise to the network */ - addresses: AddressManagerInit + addresses?: AddressManagerInit /** * libp2p Connection Manager configuration */ - connectionManager: ConnectionManagerInit + connectionManager?: ConnectionManagerInit /** * A connection gater can deny new connections based on user criteria */ - connectionGater: ConnectionGater + connectionGater?: ConnectionGater /** * libp2p transport manager configuration */ - transportManager: TransportManagerInit + transportManager?: TransportManagerInit /** * An optional datastore to persist peer information, DHT records, etc. * * An in-memory datastore will be used if one is not provided. */ - datastore: Datastore + datastore?: Datastore /** * libp2p PeerStore configuration */ - peerStore: PersistentPeerStoreInit + peerStore?: PersistentPeerStoreInit /** * An array that must include at least 1 compliant transport @@ -102,7 +102,7 @@ export interface Libp2pInit /** * Arbitrary libp2p modules */ - services: ServiceFactoryMap + services?: ServiceFactoryMap /** * An optional logging implementation that can be used to write runtime logs. @@ -135,7 +135,7 @@ export interface Libp2pInit export type { Libp2p } -export type Libp2pOptions> = RecursivePartial> & { start?: boolean } +export type Libp2pOptions> = Libp2pInit & { start?: boolean } /** * Returns a new instance of the Libp2p interface, generating a new PeerId diff --git a/packages/libp2p/src/libp2p.ts b/packages/libp2p/src/libp2p.ts index 351460092e..424472a92e 100644 --- a/packages/libp2p/src/libp2p.ts +++ b/packages/libp2p/src/libp2p.ts @@ -37,10 +37,10 @@ export class Libp2pNode> extends public logger: ComponentLogger public status: Libp2pStatus - public components: Components + public components: Components & T[keyof T] private readonly log: Logger - constructor (init: Libp2pInit) { + constructor (init: Libp2pInit & Required, 'peerId'>>) { super() this.status = 'stopped' @@ -66,6 +66,7 @@ export class Libp2pNode> extends this.log = this.logger.forComponent('libp2p') // @ts-expect-error {} may not be of type T this.services = {} + // @ts-expect-error defaultComponents is missing component types added later const components = this.components = defaultComponents({ peerId: init.peerId, privateKey: init.privateKey, @@ -111,7 +112,7 @@ export class Libp2pNode> extends this.components.upgrader = new DefaultUpgrader(this.components, { connectionEncryption: (init.connectionEncryption ?? []).map((fn, index) => this.configureComponent(`connection-encryption-${index}`, fn(this.components))), muxers: (init.streamMuxers ?? []).map((fn, index) => this.configureComponent(`stream-muxers-${index}`, fn(this.components))), - inboundUpgradeTimeout: init.connectionManager.inboundUpgradeTimeout + inboundUpgradeTimeout: init.connectionManager?.inboundUpgradeTimeout }) // Setup the transport manager @@ -159,6 +160,7 @@ export class Libp2pNode> extends if (init.services != null) { for (const name of Object.keys(init.services)) { const createService = init.services[name] + // @ts-expect-error components type is not fully formed yet const service: any = createService(this.components) if (service == null) { @@ -194,6 +196,7 @@ export class Libp2pNode> extends this.log.error('component %s was null or undefined', name) } + // @ts-expect-error cannot assign props this.components[name] = component return component @@ -413,7 +416,7 @@ export async function createLibp2pNode { describe('libp2p.dialer (direct, TCP)', () => { let peerId: PeerId let remotePeerId: PeerId - let libp2p: Libp2pNode - let remoteLibp2p: Libp2pNode + let libp2p: Libp2p + let remoteLibp2p: Libp2p let remoteAddr: Multiaddr beforeEach(async () => { @@ -291,7 +292,7 @@ describe('libp2p.dialer (direct, TCP)', () => { createEd25519PeerId() ]) - remoteLibp2p = await createLibp2pNode({ + remoteLibp2p = await createLibp2p({ peerId: remotePeerId, addresses: { listen: [listenAddr.toString()] @@ -565,6 +566,7 @@ describe('libp2p.dialer (direct, TCP)', () => { const dials = 10 const error = new Error('Boom') + // @ts-expect-error private field access Sinon.stub(libp2p.components.transportManager, 'dial').callsFake(async () => Promise.reject(error)) await libp2p.peerStore.patch(remotePeerId, { diff --git a/packages/libp2p/test/connection-manager/index.node.ts b/packages/libp2p/test/connection-manager/index.node.ts index 39d2ee5bf0..cebad403d3 100644 --- a/packages/libp2p/test/connection-manager/index.node.ts +++ b/packages/libp2p/test/connection-manager/index.node.ts @@ -419,8 +419,8 @@ describe('libp2p.connections', () => { }) describe('connection gater', () => { - let libp2p: Libp2pNode - let remoteLibp2p: Libp2pNode + let libp2p: Libp2p + let remoteLibp2p: Libp2p beforeEach(async () => { remoteLibp2p = await createNode({ @@ -485,7 +485,7 @@ describe('libp2p.connections', () => { await libp2p.peerStore.patch(remoteLibp2p.peerId, { multiaddrs: remoteLibp2p.getMultiaddrs() }) - await libp2p.components.connectionManager.openConnection(remoteLibp2p.peerId) + await libp2p.dial(remoteLibp2p.peerId) for (const multiaddr of remoteLibp2p.getMultiaddrs()) { expect(denyDialMultiaddr.calledWith(multiaddr)).to.be.true() diff --git a/packages/libp2p/test/registrar/protocols.spec.ts b/packages/libp2p/test/registrar/protocols.spec.ts index 698cfcdd08..d1ba4ef0d9 100644 --- a/packages/libp2p/test/registrar/protocols.spec.ts +++ b/packages/libp2p/test/registrar/protocols.spec.ts @@ -9,10 +9,10 @@ import { expect } from 'aegir/chai' import pDefer from 'p-defer' import { createLibp2pNode } from '../../src/libp2p.js' import type { Components } from '../../src/components.js' -import type { Libp2pNode } from '../../src/libp2p.js' +import type { Libp2p } from '@libp2p/interface' describe('registrar protocols', () => { - let libp2p: Libp2pNode + let libp2p: Libp2p it('should be able to register and unregister a handler', async () => { const deferred = pDefer() diff --git a/packages/metrics-devtools/src/index.ts b/packages/metrics-devtools/src/index.ts index a0118a4543..2148599596 100644 --- a/packages/metrics-devtools/src/index.ts +++ b/packages/metrics-devtools/src/index.ts @@ -20,7 +20,7 @@ import { start, stop } from '@libp2p/interface' import { enable, disable } from '@libp2p/logger' import { simpleMetrics } from '@libp2p/simple-metrics' import { base64 } from 'multiformats/bases/base64' -import type { ComponentLogger, Connection, Libp2pEvents, Logger, Metrics, MultiaddrConnection, PeerId, Peer as PeerStorePeer, PeerStore, PeerUpdate, Stream, TypedEventEmitter } from '@libp2p/interface' +import type { ComponentLogger, Connection, Libp2pEvents, Logger, Metrics, MultiaddrConnection, PeerId, Peer as PeerStorePeer, PeerStore, PeerUpdate, Stream, TypedEventTarget } from '@libp2p/interface' import type { TransportManager, Registrar, ConnectionManager } from '@libp2p/interface-internal' export const SOURCE_DEVTOOLS = '@libp2p/devtools-metrics:devtools' @@ -214,7 +214,7 @@ export interface DevToolsMetricsInit { export interface DevToolsMetricsComponents { logger: ComponentLogger - events: TypedEventEmitter + events: TypedEventTarget peerId: PeerId transportManager: TransportManager registrar: Registrar diff --git a/packages/peer-store/src/index.ts b/packages/peer-store/src/index.ts index 368def78c1..9c5e91d3dc 100644 --- a/packages/peer-store/src/index.ts +++ b/packages/peer-store/src/index.ts @@ -22,7 +22,7 @@ export interface PersistentPeerStoreComponents { * Return true to allow storing the passed multiaddr for the passed peer */ export interface AddressFilter { - (peerId: PeerId, multiaddr: Multiaddr): Promise + (peerId: PeerId, multiaddr: Multiaddr): Promise | boolean } export interface PersistentPeerStoreInit { diff --git a/packages/transport-circuit-relay-v2/src/server/reservation-store.ts b/packages/transport-circuit-relay-v2/src/server/reservation-store.ts index f5873d838b..e3bc8192b7 100644 --- a/packages/transport-circuit-relay-v2/src/server/reservation-store.ts +++ b/packages/transport-circuit-relay-v2/src/server/reservation-store.ts @@ -2,7 +2,7 @@ import { PeerMap } from '@libp2p/peer-collections' import { DEFAULT_DATA_LIMIT, DEFAULT_DURATION_LIMIT, DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL, DEFAULT_MAX_RESERVATION_STORE_SIZE, DEFAULT_MAX_RESERVATION_TTL } from '../constants.js' import { type Limit, Status } from '../pb/index.js' import type { RelayReservation } from '../index.js' -import type { RecursivePartial, PeerId, Startable } from '@libp2p/interface' +import type { PeerId, Startable } from '@libp2p/interface' import type { Multiaddr } from '@multiformats/multiaddr' export type ReservationStatus = Status.OK | Status.PERMISSION_DENIED | Status.RESERVATION_REFUSED @@ -34,8 +34,6 @@ export interface ReservationStoreInit { defaultDataLimit?: bigint } -export type ReservationStoreOptions = RecursivePartial - export class ReservationStore implements Startable { public readonly reservations = new PeerMap() private _started = false @@ -47,7 +45,7 @@ export class ReservationStore implements Startable { private readonly defaultDurationLimit: number private readonly defaultDataLimit: bigint - constructor (options: ReservationStoreOptions = {}) { + constructor (options: ReservationStoreInit = {}) { this.maxReservations = options.maxReservations ?? DEFAULT_MAX_RESERVATION_STORE_SIZE this.reservationClearInterval = options.reservationClearInterval ?? DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL this.applyDefaultLimit = options.applyDefaultLimit !== false