@helia/delegated-routing-v1-http-api-client 5.1.1 → 5.1.2

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/src/client.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { NotFoundError, contentRoutingSymbol, peerRoutingSymbol, setMaxListeners } from '@libp2p/interface'
2
- import { logger } from '@libp2p/logger'
3
2
  import { peerIdFromString } from '@libp2p/peer-id'
4
3
  import { multiaddr } from '@multiformats/multiaddr'
5
4
  import { anySignal } from 'any-signal'
@@ -11,14 +10,12 @@ import defer from 'p-defer'
11
10
  import PQueue from 'p-queue'
12
11
  import { BadResponseError, InvalidRequestError } from './errors.js'
13
12
  import { DelegatedRoutingV1HttpApiClientContentRouting, DelegatedRoutingV1HttpApiClientPeerRouting } from './routings.js'
14
- import type { DelegatedRoutingV1HttpApiClient, DelegatedRoutingV1HttpApiClientInit, GetProvidersOptions, GetPeersOptions, GetIPNSOptions, PeerRecord } from './index.js'
15
- import type { ContentRouting, PeerRouting, AbortOptions, PeerId } from '@libp2p/interface'
13
+ import type { DelegatedRoutingV1HttpApiClient as DelegatedRoutingV1HttpApiClientInterface, DelegatedRoutingV1HttpApiClientInit, GetProvidersOptions, GetPeersOptions, GetIPNSOptions, PeerRecord, DelegatedRoutingV1HttpApiClientComponents } from './index.js'
14
+ import type { ContentRouting, PeerRouting, AbortOptions, PeerId, Logger } from '@libp2p/interface'
16
15
  import type { Multiaddr } from '@multiformats/multiaddr'
17
16
  import type { IPNSRecord } from 'ipns'
18
17
  import type { CID } from 'multiformats'
19
18
 
20
- const log = logger('delegated-routing-v1-http-api-client')
21
-
22
19
  const defaultValues = {
23
20
  concurrentRequests: 4,
24
21
  timeout: 30e3,
@@ -26,11 +23,11 @@ const defaultValues = {
26
23
  cacheName: 'delegated-routing-v1-cache'
27
24
  }
28
25
 
29
- export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV1HttpApiClient {
26
+ export class DelegatedRoutingV1HttpApiClient implements DelegatedRoutingV1HttpApiClientInterface {
27
+ public readonly url: URL
30
28
  private started: boolean
31
29
  private readonly httpQueue: PQueue
32
30
  private readonly shutDownController: AbortController
33
- private readonly clientUrl: URL
34
31
  private readonly timeout: number
35
32
  private readonly contentRouting: ContentRouting
36
33
  private readonly peerRouting: PeerRouting
@@ -40,10 +37,13 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
40
37
  private readonly cacheName: string
41
38
  private cache?: Cache
42
39
  private readonly cacheTTL: number
40
+ private log: Logger
41
+
43
42
  /**
44
43
  * Create a new DelegatedContentRouting instance
45
44
  */
46
- constructor (url: string | URL, init: DelegatedRoutingV1HttpApiClientInit = {}) {
45
+ constructor (components: DelegatedRoutingV1HttpApiClientComponents, init: DelegatedRoutingV1HttpApiClientInit & { url: string | URL }) {
46
+ this.log = components.logger.forComponent('delegated-routing-v1-http-api-client')
47
47
  this.started = false
48
48
  this.shutDownController = new AbortController()
49
49
  setMaxListeners(Infinity, this.shutDownController.signal)
@@ -51,7 +51,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
51
51
  concurrency: init.concurrentRequests ?? defaultValues.concurrentRequests
52
52
  })
53
53
  this.inFlightRequests = new Map() // Tracks in-flight requests to avoid duplicate requests
54
- this.clientUrl = url instanceof URL ? url : new URL(url)
54
+ this.url = init.url instanceof URL ? init.url : new URL(init.url)
55
55
  this.timeout = init.timeout ?? defaultValues.timeout
56
56
  this.filterAddrs = init.filterAddrs
57
57
  this.filterProtocols = init.filterProtocols
@@ -85,7 +85,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
85
85
  this.cache = await globalThis.caches?.open(this.cacheName)
86
86
 
87
87
  if (this.cache != null) {
88
- log('cache enabled with ttl %d', this.cacheTTL)
88
+ this.log('cache enabled with ttl %d', this.cacheTTL)
89
89
  }
90
90
  }
91
91
  }
@@ -101,7 +101,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
101
101
  }
102
102
 
103
103
  async * getProviders (cid: CID, options: GetProvidersOptions = {}): AsyncGenerator<PeerRecord> {
104
- log('getProviders starts: %c', cid)
104
+ this.log('getProviders starts: %c', cid)
105
105
 
106
106
  const timeoutSignal = AbortSignal.timeout(this.timeout)
107
107
  const signal = anySignal([this.shutDownController.signal, timeoutSignal, options.signal])
@@ -118,7 +118,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
118
118
  await onStart.promise
119
119
 
120
120
  // https://specs.ipfs.tech/routing/http-routing-v1/
121
- const url = new URL(`${this.clientUrl}routing/v1/providers/${cid}`)
121
+ const url = new URL(`${this.url}routing/v1/providers/${cid}`)
122
122
 
123
123
  this.#addFilterParams(url, options.filterAddrs, options.filterProtocols)
124
124
  const getOptions = { headers: { Accept: 'application/x-ndjson' }, signal }
@@ -175,12 +175,12 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
175
175
  } finally {
176
176
  signal.clear()
177
177
  onFinish.resolve()
178
- log('getProviders finished: %c', cid)
178
+ this.log('getProviders finished: %c', cid)
179
179
  }
180
180
  }
181
181
 
182
182
  async * getPeers (peerId: PeerId, options: GetPeersOptions = {}): AsyncGenerator<PeerRecord> {
183
- log('getPeers starts: %c', peerId)
183
+ this.log('getPeers starts: %c', peerId)
184
184
 
185
185
  const timeoutSignal = AbortSignal.timeout(this.timeout)
186
186
  const signal = anySignal([this.shutDownController.signal, timeoutSignal, options.signal])
@@ -197,7 +197,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
197
197
  await onStart.promise
198
198
 
199
199
  // https://specs.ipfs.tech/routing/http-routing-v1/
200
- const url = new URL(`${this.clientUrl}routing/v1/peers/${peerId.toCID().toString()}`)
200
+ const url = new URL(`${this.url}routing/v1/peers/${peerId.toCID().toString()}`)
201
201
  this.#addFilterParams(url, options.filterAddrs, options.filterProtocols)
202
202
 
203
203
  const getOptions = { headers: { Accept: 'application/x-ndjson' }, signal }
@@ -241,16 +241,16 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
241
241
  }
242
242
  }
243
243
  } catch (err) {
244
- log.error('getPeers errored:', err)
244
+ this.log.error('getPeers errored - %e', err)
245
245
  } finally {
246
246
  signal.clear()
247
247
  onFinish.resolve()
248
- log('getPeers finished: %c', peerId)
248
+ this.log('getPeers finished: %c', peerId)
249
249
  }
250
250
  }
251
251
 
252
252
  async getIPNS (libp2pKey: CID<unknown, 0x72, 0x00 | 0x12, 1>, options: GetIPNSOptions = {}): Promise<IPNSRecord> {
253
- log('getIPNS starts: %s', libp2pKey)
253
+ this.log('getIPNS starts: %s', libp2pKey)
254
254
 
255
255
  const timeoutSignal = AbortSignal.timeout(this.timeout)
256
256
  const signal = anySignal([this.shutDownController.signal, timeoutSignal, options.signal])
@@ -264,7 +264,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
264
264
  })
265
265
 
266
266
  // https://specs.ipfs.tech/routing/http-routing-v1/
267
- const resource = `${this.clientUrl}routing/v1/ipns/${libp2pKey}`
267
+ const resource = `${this.url}routing/v1/ipns/${libp2pKey}`
268
268
 
269
269
  try {
270
270
  await onStart.promise
@@ -272,7 +272,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
272
272
  const getOptions = { headers: { Accept: 'application/vnd.ipfs.ipns-record' }, signal }
273
273
  const res = await this.#makeRequest(resource, getOptions)
274
274
 
275
- log('getIPNS GET %s %d', resource, res.status)
275
+ this.log('getIPNS GET %s %d', resource, res.status)
276
276
 
277
277
  // Per IPIP-0513: Handle 404 as "no record found" for backward compatibility
278
278
  // IPNS is different - we still throw NotFoundError for 404 (backward compat)
@@ -311,18 +311,18 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
311
311
 
312
312
  return unmarshalIPNSRecord(body)
313
313
  } catch (err: any) {
314
- log.error('getIPNS GET %s error:', resource, err)
314
+ this.log.error('getIPNS GET %s error - %e', resource, err)
315
315
 
316
316
  throw err
317
317
  } finally {
318
318
  signal.clear()
319
319
  onFinish.resolve()
320
- log('getIPNS finished: %s', libp2pKey)
320
+ this.log('getIPNS finished: %s', libp2pKey)
321
321
  }
322
322
  }
323
323
 
324
324
  async putIPNS (libp2pKey: CID<unknown, 0x72, 0x00 | 0x12, 1>, record: IPNSRecord, options: AbortOptions = {}): Promise<void> {
325
- log('putIPNS starts: %c', libp2pKey)
325
+ this.log('putIPNS starts: %c', libp2pKey)
326
326
 
327
327
  const timeoutSignal = AbortSignal.timeout(this.timeout)
328
328
  const signal = anySignal([this.shutDownController.signal, timeoutSignal, options.signal])
@@ -336,7 +336,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
336
336
  })
337
337
 
338
338
  // https://specs.ipfs.tech/routing/http-routing-v1/
339
- const resource = `${this.clientUrl}routing/v1/ipns/${libp2pKey}`
339
+ const resource = `${this.url}routing/v1/ipns/${libp2pKey}`
340
340
 
341
341
  try {
342
342
  await onStart.promise
@@ -346,19 +346,19 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
346
346
  const getOptions = { method: 'PUT', headers: { 'Content-Type': 'application/vnd.ipfs.ipns-record' }, body, signal }
347
347
  const res = await this.#makeRequest(resource, getOptions)
348
348
 
349
- log('putIPNS PUT %s %d', resource, res.status)
349
+ this.log('putIPNS PUT %s %d', resource, res.status)
350
350
 
351
351
  if (res.status !== 200) {
352
352
  throw new BadResponseError('PUT ipns response had status other than 200')
353
353
  }
354
354
  } catch (err: any) {
355
- log.error('putIPNS PUT %s error:', resource, err.stack)
355
+ this.log.error('putIPNS PUT %s error - %e', resource, err.stack)
356
356
 
357
357
  throw err
358
358
  } finally {
359
359
  signal.clear()
360
360
  onFinish.resolve()
361
- log('putIPNS finished: %c', libp2pKey)
361
+ this.log('putIPNS finished: %c', libp2pKey)
362
362
  }
363
363
  }
364
364
 
@@ -384,7 +384,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
384
384
  Protocols: protocols
385
385
  }
386
386
  } catch (err) {
387
- log.error('could not conform record to peer schema', err)
387
+ this.log.error('could not conform record to peer schema - %e', err)
388
388
  }
389
389
  }
390
390
 
@@ -420,7 +420,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
420
420
  // Check if the cached response has expired
421
421
  const expires = parseInt(cachedResponse.headers.get('x-cache-expires') ?? '0', 10)
422
422
  if (expires > Date.now()) {
423
- log('returning cached response for %s', key)
423
+ this.log('returning cached response for %s', key)
424
424
  return cachedResponse
425
425
  } else {
426
426
  // Remove expired response from cache
@@ -433,7 +433,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
433
433
  const existingRequest = this.inFlightRequests.get(key)
434
434
  if (existingRequest != null) {
435
435
  const response = await existingRequest
436
- log('deduplicating outgoing request for %s', key)
436
+ this.log('deduplicating outgoing request for %s', key)
437
437
  return response.clone()
438
438
  }
439
439
 
@@ -464,4 +464,8 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
464
464
  const response = await requestPromise
465
465
  return response
466
466
  }
467
+
468
+ toString (): string {
469
+ return `DefaultDelegatedRoutingV1HttpApiClient(${this.url})`
470
+ }
467
471
  }
package/src/index.ts CHANGED
@@ -83,8 +83,9 @@
83
83
  * ```
84
84
  */
85
85
 
86
- import { DefaultDelegatedRoutingV1HttpApiClient } from './client.js'
87
- import type { AbortOptions, PeerId } from '@libp2p/interface'
86
+ import { defaultLogger } from '@libp2p/logger'
87
+ import { DelegatedRoutingV1HttpApiClient as DelegatedRoutingV1HttpApiClientClass } from './client.js'
88
+ import type { AbortOptions, ComponentLogger, PeerId } from '@libp2p/interface'
88
89
  import type { Multiaddr } from '@multiformats/multiaddr'
89
90
  import type { IPNSRecord } from 'ipns'
90
91
  import type { CID } from 'multiformats/cid'
@@ -155,6 +156,10 @@ export interface DelegatedRoutingV1HttpApiClientInit extends FilterOptions {
155
156
  cacheName?: string
156
157
  }
157
158
 
159
+ export interface DelegatedRoutingV1HttpApiClientComponents {
160
+ logger: ComponentLogger
161
+ }
162
+
158
163
  export interface GetIPNSOptions extends AbortOptions {
159
164
  /**
160
165
  * By default incoming IPNS records are validated, pass false here to skip
@@ -169,6 +174,11 @@ export type GetProvidersOptions = FilterOptions & AbortOptions
169
174
  export type GetPeersOptions = FilterOptions & AbortOptions
170
175
 
171
176
  export interface DelegatedRoutingV1HttpApiClient {
177
+ /**
178
+ * The URL that requests are sent to
179
+ */
180
+ url: URL
181
+
172
182
  /**
173
183
  * Returns an async generator of {@link PeerRecord}s that can provide the
174
184
  * content for the passed {@link CID}
@@ -206,7 +216,23 @@ export interface DelegatedRoutingV1HttpApiClient {
206
216
 
207
217
  /**
208
218
  * Create and return a client to use with a Routing V1 HTTP API server
219
+ *
220
+ * @deprecated use `delegatedRoutingV1HttpApiClient` instead - this function will be removed in a future release
221
+ */
222
+ export function createDelegatedRoutingV1HttpApiClient (url: URL | string, init: Omit<DelegatedRoutingV1HttpApiClientInit, 'url'> = {}): DelegatedRoutingV1HttpApiClient {
223
+ return new DelegatedRoutingV1HttpApiClientClass({
224
+ logger: defaultLogger()
225
+ }, {
226
+ ...init,
227
+ url: new URL(url)
228
+ })
229
+ }
230
+
231
+ /**
232
+ * Create and return a client to use with a Routing V1 HTTP API server
233
+ *
234
+ * TODO: add `url` to `DelegatedRoutingV1HttpApiClientInit` interface and release as breaking change
209
235
  */
210
- export function createDelegatedRoutingV1HttpApiClient (url: URL | string, init: DelegatedRoutingV1HttpApiClientInit = {}): DelegatedRoutingV1HttpApiClient {
211
- return new DefaultDelegatedRoutingV1HttpApiClient(new URL(url), init)
236
+ export function delegatedRoutingV1HttpApiClient (init: DelegatedRoutingV1HttpApiClientInit & { url: string | URL }): (components: DelegatedRoutingV1HttpApiClientComponents) => DelegatedRoutingV1HttpApiClient {
237
+ return (components) => new DelegatedRoutingV1HttpApiClientClass(components, init)
212
238
  }
package/src/routings.ts CHANGED
@@ -86,6 +86,10 @@ export class DelegatedRoutingV1HttpApiClientContentRouting implements ContentRou
86
86
  throw err
87
87
  }
88
88
  }
89
+
90
+ toString (): string {
91
+ return `DelegatedRoutingV1HttpApiClientContentRouting(${this.client.url})`
92
+ }
89
93
  }
90
94
 
91
95
  /**
@@ -114,4 +118,8 @@ export class DelegatedRoutingV1HttpApiClientPeerRouting implements PeerRouting {
114
118
  async * getClosestPeers (key: Uint8Array, options: AbortOptions = {}): AsyncIterable<PeerInfo> {
115
119
  // noop
116
120
  }
121
+
122
+ toString (): string {
123
+ return `DelegatedRoutingV1HttpApiClientPeerRouting(${this.client.url})`
124
+ }
117
125
  }