@helia/libp2p 0.0.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.
Files changed (35) hide show
  1. package/README.md +83 -0
  2. package/dist/index.min.js +177 -0
  3. package/dist/index.min.js.map +7 -0
  4. package/dist/src/index.d.ts +35 -0
  5. package/dist/src/index.d.ts.map +1 -0
  6. package/dist/src/index.js +74 -0
  7. package/dist/src/index.js.map +1 -0
  8. package/dist/src/routing.d.ts +4 -0
  9. package/dist/src/routing.d.ts.map +1 -0
  10. package/dist/src/routing.js +46 -0
  11. package/dist/src/routing.js.map +1 -0
  12. package/dist/src/utils/bootstrappers.d.ts +4 -0
  13. package/dist/src/utils/bootstrappers.d.ts.map +1 -0
  14. package/dist/src/utils/bootstrappers.js +13 -0
  15. package/dist/src/utils/bootstrappers.js.map +1 -0
  16. package/dist/src/utils/libp2p-defaults.browser.d.ts +18 -0
  17. package/dist/src/utils/libp2p-defaults.browser.d.ts.map +1 -0
  18. package/dist/src/utils/libp2p-defaults.browser.js +66 -0
  19. package/dist/src/utils/libp2p-defaults.browser.js.map +1 -0
  20. package/dist/src/utils/libp2p-defaults.d.ts +50 -0
  21. package/dist/src/utils/libp2p-defaults.d.ts.map +1 -0
  22. package/dist/src/utils/libp2p-defaults.js +107 -0
  23. package/dist/src/utils/libp2p-defaults.js.map +1 -0
  24. package/dist/src/utils/libp2p.d.ts +17 -0
  25. package/dist/src/utils/libp2p.d.ts.map +1 -0
  26. package/dist/src/utils/libp2p.js +22 -0
  27. package/dist/src/utils/libp2p.js.map +1 -0
  28. package/dist/typedoc-urls.json +9 -0
  29. package/package.json +88 -0
  30. package/src/index.ts +103 -0
  31. package/src/routing.ts +60 -0
  32. package/src/utils/bootstrappers.ts +12 -0
  33. package/src/utils/libp2p-defaults.browser.ts +85 -0
  34. package/src/utils/libp2p-defaults.ts +133 -0
  35. package/src/utils/libp2p.ts +43 -0
package/src/index.ts ADDED
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * Adds libp2p functionality to Helia
5
+ *
6
+ * @example
7
+ *
8
+ * ```ts
9
+ * import { createHelia } from 'helia'
10
+ * import { withLibp2p } from '@helia/libp2p'
11
+ *
12
+ * const node = await withLibp2p(createHelia()).start()
13
+ *
14
+ * console.info(node.libp2p.peerId) // 12D3Koo...
15
+ * ```
16
+ */
17
+
18
+ import { NotStartedError } from '@libp2p/interface'
19
+ import { isLibp2p } from 'libp2p'
20
+ import { libp2pRouting } from './routing.ts'
21
+ import { createLibp2p } from './utils/libp2p.ts'
22
+ import type { DefaultLibp2pServices } from './utils/libp2p-defaults.ts'
23
+ import type { CreateLibp2pOptions } from './utils/libp2p.ts'
24
+ import type { Helia, HeliaMixin } from '@helia/interface'
25
+ import type { Libp2p, ServiceMap } from '@libp2p/interface'
26
+
27
+ export { libp2pDefaults } from './utils/libp2p-defaults.ts'
28
+ export type { DefaultLibp2pServices } from './utils/libp2p-defaults.ts'
29
+ export type { CreateLibp2pOptions }
30
+
31
+ export interface HeliaWithLibp2p<M extends ServiceMap = DefaultLibp2pServices> extends Helia {
32
+ /**
33
+ * Libp2p provides a peer identity and a networking layer
34
+ */
35
+ libp2p: Libp2p<M>
36
+ }
37
+
38
+ async function getLibp2p <H extends Helia, M extends ServiceMap = ServiceMap> (helia: H, opts?: CreateLibp2pOptions<M>): Promise<Libp2p<M>> {
39
+ if (isLibp2p(opts)) {
40
+ return opts as any
41
+ }
42
+
43
+ return createLibp2p(helia, {
44
+ ...opts,
45
+ dns: helia.dns,
46
+ logger: helia.logger,
47
+ datastore: helia.datastore
48
+ })
49
+ }
50
+
51
+ /**
52
+ * Return a Helia node augmented with a libp2p instance
53
+ */
54
+ export function withLibp2p <H extends Helia, M extends ServiceMap = ServiceMap, L extends Libp2p = Libp2p<M>> (helia: H, opts: L): HeliaWithLibp2p<M>
55
+ export function withLibp2p <H extends Helia, M extends ServiceMap = ServiceMap> (helia: H, opts?: CreateLibp2pOptions<M>): HeliaWithLibp2p<M>
56
+ export function withLibp2p <H extends Helia, M extends ServiceMap = ServiceMap> (helia: H, opts?: CreateLibp2pOptions<M>): HeliaWithLibp2p {
57
+ let libp2p: any
58
+
59
+ // add a getter that informs the user they need to start Helia
60
+ Object.defineProperty(helia, 'libp2p', {
61
+ configurable: true,
62
+ enumerable: true,
63
+ get () {
64
+ if (libp2p != null) {
65
+ return libp2p
66
+ }
67
+
68
+ throw new NotStartedError()
69
+ }
70
+ })
71
+
72
+ const mixin: HeliaMixin<H & { libp2p?: Libp2p<M> }, H & { libp2p?: Libp2p<M> }> = {
73
+ start: async (helia) => {
74
+ if (libp2p == null) {
75
+ libp2p = await getLibp2p(helia, opts)
76
+ }
77
+
78
+ try {
79
+ if (!helia.hasRouter('libp2p-router')) {
80
+ helia.addRouter(libp2pRouting(libp2p))
81
+ }
82
+
83
+ if (isLibp2p(helia.libp2p)) {
84
+ // already configured libp2p
85
+ await helia.libp2p.start()
86
+ }
87
+ } catch (err: any) {
88
+ if (err.name !== 'NotStartedError') {
89
+ throw err
90
+ }
91
+ }
92
+ },
93
+
94
+ stop: async () => {
95
+ await libp2p?.stop()
96
+ }
97
+ }
98
+
99
+ helia.addMixin(mixin)
100
+
101
+ // @ts-expect-error libp2p property is missing, even though we just defined it
102
+ return helia
103
+ }
package/src/routing.ts ADDED
@@ -0,0 +1,60 @@
1
+ import { peerIdFromCID } from '@libp2p/peer-id'
2
+ import map from 'it-map'
3
+ import type { Peer, Provider, Router, RoutingOptions } from '@helia/interface'
4
+ import type { Libp2p, PeerInfo } from '@libp2p/interface'
5
+ import type { CID } from 'multiformats'
6
+
7
+ function peerInfoToPeer (info: PeerInfo): Peer {
8
+ return {
9
+ ...info,
10
+ id: info.id.toCID()
11
+ }
12
+ }
13
+
14
+ class Libp2pRouter implements Router {
15
+ public readonly name = 'libp2p-router'
16
+ private readonly libp2p: Libp2p
17
+
18
+ constructor (libp2p: Libp2p) {
19
+ this.libp2p = libp2p
20
+ }
21
+
22
+ async provide (cid: CID, options?: RoutingOptions): Promise<void> {
23
+ await this.libp2p.contentRouting.provide(cid, options)
24
+ }
25
+
26
+ async cancelReprovide (key: CID, options?: RoutingOptions): Promise<void> {
27
+ await this.libp2p.contentRouting.cancelReprovide(key, options)
28
+ }
29
+
30
+ async * findProviders (cid: CID, options?: RoutingOptions): AsyncIterable<Provider> {
31
+ yield * map(this.libp2p.contentRouting.findProviders(cid, options), prov => ({
32
+ routing: this.name,
33
+ ...peerInfoToPeer(prov)
34
+ }))
35
+ }
36
+
37
+ async put (key: Uint8Array, value: Uint8Array, options?: RoutingOptions): Promise<void> {
38
+ await this.libp2p.contentRouting.put(key, value, options)
39
+ }
40
+
41
+ async get (key: Uint8Array, options?: RoutingOptions): Promise<Uint8Array> {
42
+ return this.libp2p.contentRouting.get(key, options)
43
+ }
44
+
45
+ async findPeer (peerId: CID, options?: RoutingOptions): Promise<Peer> {
46
+ return peerInfoToPeer(await this.libp2p.peerRouting.findPeer(peerIdFromCID(peerId), options))
47
+ }
48
+
49
+ async * getClosestPeers (key: Uint8Array, options?: RoutingOptions): AsyncIterable<Peer> {
50
+ yield * map(this.libp2p.peerRouting.getClosestPeers(key, options), peerInfoToPeer)
51
+ }
52
+
53
+ toString (): string {
54
+ return 'Libp2pRouter()'
55
+ }
56
+ }
57
+
58
+ export function libp2pRouting (libp2p: Libp2p): Router {
59
+ return new Libp2pRouter(libp2p)
60
+ }
@@ -0,0 +1,12 @@
1
+ // this list comes from https://github.com/ipfs/kubo/blob/da28fbc65a2e0f1ce59f9923823326ae2bc4f713/config/bootstrap_peers.go#L17
2
+ export const bootstrapConfig = {
3
+ list: [
4
+ '/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
5
+ '/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
6
+ '/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt',
7
+ // va1 is not in the TXT records for _dnsaddr.bootstrap.libp2p.io yet
8
+ // so use the host name directly
9
+ '/dnsaddr/va1.bootstrap.libp2p.io/p2p/12D3KooWKnDdG3iXw9eTFijk3EWSunZcFi54Zka4wmtqtt6rPxc8',
10
+ '/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ'
11
+ ]
12
+ }
@@ -0,0 +1,85 @@
1
+ import { noise } from '@chainsafe/libp2p-noise'
2
+ import { yamux } from '@chainsafe/libp2p-yamux'
3
+ import { delegatedHTTPRoutingDefaults } from '@helia/delegated-routing-client'
4
+ import { delegatedRoutingV1HttpApiClientContentRouting, delegatedRoutingV1HttpApiClientPeerRouting } from '@helia/delegated-routing-v1-http-api-client'
5
+ import { autoNAT } from '@libp2p/autonat'
6
+ import { bootstrap } from '@libp2p/bootstrap'
7
+ import { circuitRelayTransport } from '@libp2p/circuit-relay-v2'
8
+ import { dcutr } from '@libp2p/dcutr'
9
+ import { http } from '@libp2p/http'
10
+ import { identify, identifyPush } from '@libp2p/identify'
11
+ import { kadDHT } from '@libp2p/kad-dht'
12
+ import { mplex } from '@libp2p/mplex'
13
+ import { ping } from '@libp2p/ping'
14
+ import { webRTC, webRTCDirect } from '@libp2p/webrtc'
15
+ import { webSockets } from '@libp2p/websockets'
16
+ import { userAgent } from 'libp2p/user-agent'
17
+ import { bootstrapConfig } from './bootstrappers.ts'
18
+ import type { Libp2pDefaultsOptions } from './libp2p.ts'
19
+ import type { HTTP } from '@libp2p/http'
20
+ import type { Identify } from '@libp2p/identify'
21
+ import type { KadDHT } from '@libp2p/kad-dht'
22
+ import type { Ping } from '@libp2p/ping'
23
+ import type { Libp2pOptions } from 'libp2p'
24
+
25
+ export interface DefaultLibp2pServices extends Record<string, unknown> {
26
+ autoNAT: unknown
27
+ dcutr: unknown
28
+ delegatedContentRouting: unknown
29
+ delegatedPeerRouting: unknown
30
+ dht: KadDHT
31
+ identify: Identify
32
+ ping: Ping
33
+ http: HTTP
34
+ }
35
+
36
+ export function libp2pDefaults (options: Libp2pDefaultsOptions = {}): Libp2pOptions<DefaultLibp2pServices> & Required<Pick<Libp2pOptions<DefaultLibp2pServices>, 'services'>> {
37
+ let agentVersion: string | undefined
38
+
39
+ if (options.name != null && options.version != null) {
40
+ agentVersion = `${options.name}/${options.version} ${userAgent()}`
41
+ }
42
+
43
+ return {
44
+ privateKey: options.privateKey,
45
+ dns: options.dns,
46
+ nodeInfo: {
47
+ userAgent: agentVersion
48
+ },
49
+ addresses: {
50
+ listen: [
51
+ '/p2p-circuit',
52
+ '/webrtc'
53
+ ]
54
+ },
55
+ transports: [
56
+ circuitRelayTransport(),
57
+ webRTC(),
58
+ webRTCDirect(),
59
+ webSockets()
60
+ ],
61
+ connectionEncrypters: [
62
+ noise()
63
+ ],
64
+ streamMuxers: [
65
+ yamux(),
66
+ mplex()
67
+ ],
68
+ peerDiscovery: [
69
+ bootstrap(bootstrapConfig)
70
+ ],
71
+ services: {
72
+ autoNAT: autoNAT(),
73
+ dcutr: dcutr(),
74
+ delegatedContentRouting: delegatedRoutingV1HttpApiClientContentRouting(delegatedHTTPRoutingDefaults()),
75
+ delegatedPeerRouting: delegatedRoutingV1HttpApiClientPeerRouting(delegatedHTTPRoutingDefaults()),
76
+ dht: kadDHT({
77
+ clientMode: true
78
+ }),
79
+ identify: identify(),
80
+ identifyPush: identifyPush(),
81
+ ping: ping(),
82
+ http: http()
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,133 @@
1
+ import { noise } from '@chainsafe/libp2p-noise'
2
+ import { yamux } from '@chainsafe/libp2p-yamux'
3
+ import { delegatedHTTPRoutingDefaults } from '@helia/delegated-routing-client'
4
+ import { delegatedRoutingV1HttpApiClientContentRouting, delegatedRoutingV1HttpApiClientPeerRouting } from '@helia/delegated-routing-v1-http-api-client'
5
+ import { autoTLS } from '@ipshipyard/libp2p-auto-tls'
6
+ import { autoNAT } from '@libp2p/autonat'
7
+ import { bootstrap } from '@libp2p/bootstrap'
8
+ import { circuitRelayTransport, circuitRelayServer } from '@libp2p/circuit-relay-v2'
9
+ import { dcutr } from '@libp2p/dcutr'
10
+ import { http } from '@libp2p/http'
11
+ import { identify, identifyPush } from '@libp2p/identify'
12
+ import { kadDHT } from '@libp2p/kad-dht'
13
+ import { keychain } from '@libp2p/keychain'
14
+ import { mdns } from '@libp2p/mdns'
15
+ import { mplex } from '@libp2p/mplex'
16
+ import { ping } from '@libp2p/ping'
17
+ import { tcp } from '@libp2p/tcp'
18
+ import { tls } from '@libp2p/tls'
19
+ import { uPnPNAT } from '@libp2p/upnp-nat'
20
+ import { webRTC, webRTCDirect } from '@libp2p/webrtc'
21
+ import { webSockets } from '@libp2p/websockets'
22
+ import { userAgent } from 'libp2p/user-agent'
23
+ import { bootstrapConfig } from './bootstrappers.ts'
24
+ import type { Libp2pDefaultsOptions } from './libp2p.ts'
25
+ import type { AutoTLS } from '@ipshipyard/libp2p-auto-tls'
26
+ import type { CircuitRelayService } from '@libp2p/circuit-relay-v2'
27
+ import type { HTTP } from '@libp2p/http'
28
+ import type { Identify } from '@libp2p/identify'
29
+ import type { KadDHT } from '@libp2p/kad-dht'
30
+ import type { Keychain } from '@libp2p/keychain'
31
+ import type { Ping } from '@libp2p/ping'
32
+ import type { Libp2pOptions } from 'libp2p'
33
+
34
+ export interface DefaultLibp2pServices extends Record<string, unknown> {
35
+ autoNAT: unknown
36
+ autoTLS: AutoTLS
37
+ dcutr: unknown
38
+ delegatedContentRouting: unknown
39
+ delegatedPeerRouting: unknown
40
+ dht: KadDHT
41
+ identify: Identify
42
+ keychain: Keychain
43
+ ping: Ping
44
+ relay: CircuitRelayService
45
+ upnp: unknown
46
+ http: HTTP
47
+ }
48
+
49
+ /**
50
+ * Returns the default libp2p config used by Helia which can then be modified or
51
+ * extended to suit individual applications.
52
+ *
53
+ * @example Adding an additional libp2p service
54
+ *
55
+ * ```ts
56
+ * import { myService } from '@example/my-service'
57
+ * import { createHelia, libp2pDefaults } from 'helia'
58
+ *
59
+ * // get a copy of the default libp2p config
60
+ * const libp2p = libp2pDefaults()
61
+ *
62
+ * // add the custom service to the service map
63
+ * libp2p.services.myService = myService()
64
+ *
65
+ * // create a Helia node with the custom libp2p config
66
+ * const helia = await createHelia({
67
+ * libp2p
68
+ * })
69
+ *
70
+ * //... use service
71
+ * helia.libp2p.services.myService.serviceMethod()
72
+ * ```
73
+ */
74
+ export function libp2pDefaults (options: Libp2pDefaultsOptions = {}): Libp2pOptions<DefaultLibp2pServices> & Required<Pick<Libp2pOptions<DefaultLibp2pServices>, 'services'>> {
75
+ let agentVersion: string | undefined
76
+
77
+ if (options.name != null && options.version != null) {
78
+ agentVersion = `${options.name}/${options.version} ${userAgent()}`
79
+ }
80
+
81
+ return {
82
+ privateKey: options.privateKey,
83
+ dns: options.dns,
84
+ nodeInfo: {
85
+ userAgent: agentVersion
86
+ },
87
+ addresses: {
88
+ listen: [
89
+ '/ip4/0.0.0.0/tcp/0',
90
+ '/ip4/0.0.0.0/tcp/0/ws',
91
+ '/ip4/0.0.0.0/udp/0/webrtc-direct',
92
+ '/ip6/::/tcp/0',
93
+ '/ip6/::/tcp/0/ws',
94
+ '/ip6/::/udp/0/webrtc-direct',
95
+ '/p2p-circuit'
96
+ ]
97
+ },
98
+ transports: [
99
+ circuitRelayTransport(),
100
+ tcp(),
101
+ webRTC(),
102
+ webRTCDirect(),
103
+ webSockets()
104
+ ],
105
+ connectionEncrypters: [
106
+ noise(),
107
+ tls()
108
+ ],
109
+ streamMuxers: [
110
+ yamux(),
111
+ mplex()
112
+ ],
113
+ peerDiscovery: [
114
+ mdns(),
115
+ bootstrap(bootstrapConfig)
116
+ ],
117
+ services: {
118
+ autoNAT: autoNAT(),
119
+ autoTLS: autoTLS(),
120
+ dcutr: dcutr(),
121
+ delegatedPeerRouting: delegatedRoutingV1HttpApiClientPeerRouting(delegatedHTTPRoutingDefaults()),
122
+ delegatedContentRouting: delegatedRoutingV1HttpApiClientContentRouting(delegatedHTTPRoutingDefaults()),
123
+ dht: kadDHT(),
124
+ identify: identify(),
125
+ identifyPush: identifyPush(),
126
+ keychain: keychain(options.keychain),
127
+ ping: ping(),
128
+ relay: circuitRelayServer(),
129
+ upnp: uPnPNAT(),
130
+ http: http()
131
+ }
132
+ }
133
+ }
@@ -0,0 +1,43 @@
1
+ import { loadOrCreateSelfKey } from '@libp2p/config'
2
+ import { createLibp2p as create } from 'libp2p'
3
+ import { libp2pDefaults } from './libp2p-defaults.ts'
4
+ import type { Helia } from '@helia/interface'
5
+ import type { Libp2p, PrivateKey } from '@libp2p/interface'
6
+ import type { KeychainInit } from '@libp2p/keychain'
7
+ import type { DNS } from '@multiformats/dns'
8
+ import type { Libp2pOptions } from 'libp2p'
9
+
10
+ export interface CreateLibp2pOptions<T extends Record<string, unknown>> extends Libp2pOptions<T> {
11
+ keychain?: KeychainInit
12
+ }
13
+
14
+ export interface Libp2pDefaultsOptions {
15
+ privateKey?: PrivateKey
16
+ keychain?: KeychainInit
17
+ dns?: DNS
18
+ name?: string
19
+ version?: string
20
+ }
21
+
22
+ export async function createLibp2p <T extends Record<string, unknown>> (helia: Helia, options: CreateLibp2pOptions<T>): Promise<Libp2p<T>> {
23
+ const libp2pOptions = options ?? {}
24
+
25
+ // if no peer id was passed, try to load it from the keychain
26
+ if (libp2pOptions.privateKey == null && options.datastore != null) {
27
+ libp2pOptions.privateKey = await loadOrCreateSelfKey(options.datastore, options.keychain)
28
+ }
29
+
30
+ const defaults: any = libp2pDefaults({
31
+ ...libp2pOptions,
32
+ name: libp2pOptions.nodeInfo?.name ?? helia.info.name,
33
+ version: libp2pOptions.nodeInfo?.version ?? helia.info.version
34
+ })
35
+ defaults.datastore = defaults.datastore ?? options.datastore
36
+
37
+ const node = await create<T>({
38
+ ...defaults,
39
+ ...libp2pOptions
40
+ })
41
+
42
+ return node
43
+ }