@helia/ipns 4.0.0 → 5.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.
- package/README.md +51 -7
- package/dist/index.min.js +73 -26
- package/dist/src/index.d.ts +50 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +75 -6
- package/dist/src/index.js.map +1 -1
- package/dist/src/routing/helia.d.ts +20 -0
- package/dist/src/routing/helia.d.ts.map +1 -0
- package/dist/src/routing/helia.js +32 -0
- package/dist/src/routing/helia.js.map +1 -0
- package/dist/src/routing/index.d.ts +9 -3
- package/dist/src/routing/index.d.ts.map +1 -1
- package/dist/src/routing/index.js +1 -1
- package/dist/src/routing/index.js.map +1 -1
- package/dist/typedoc-urls.json +40 -40
- package/package.json +13 -14
- package/src/index.ts +79 -6
- package/src/routing/helia.ts +45 -0
- package/src/routing/index.ts +9 -4
- package/dist/src/routing/libp2p.d.ts +0 -22
- package/dist/src/routing/libp2p.d.ts.map +0 -1
- package/dist/src/routing/libp2p.js +0 -32
- package/dist/src/routing/libp2p.js.map +0 -1
- package/src/routing/libp2p.ts +0 -47
package/src/index.ts
CHANGED
|
@@ -3,20 +3,64 @@
|
|
|
3
3
|
*
|
|
4
4
|
* IPNS operations using a Helia node
|
|
5
5
|
*
|
|
6
|
-
* @example
|
|
6
|
+
* @example Getting started
|
|
7
7
|
*
|
|
8
8
|
* With {@link IPNSRouting} routers:
|
|
9
9
|
*
|
|
10
10
|
* ```typescript
|
|
11
11
|
* import { createHelia } from 'helia'
|
|
12
12
|
* import { ipns } from '@helia/ipns'
|
|
13
|
-
* import { libp2p, pubsub } from '@helia/ipns/routing'
|
|
14
13
|
* import { unixfs } from '@helia/unixfs'
|
|
15
14
|
*
|
|
16
15
|
* const helia = await createHelia()
|
|
16
|
+
* const name = ipns(helia)
|
|
17
|
+
*
|
|
18
|
+
* // create a public key to publish as an IPNS name
|
|
19
|
+
* const keyInfo = await helia.libp2p.services.keychain.createKey('my-key')
|
|
20
|
+
* const peerId = await helia.libp2p.services.keychain.exportPeerId(keyInfo.name)
|
|
21
|
+
*
|
|
22
|
+
* // store some data to publish
|
|
23
|
+
* const fs = unixfs(helia)
|
|
24
|
+
* const cid = await fs.add(Uint8Array.from([0, 1, 2, 3, 4]))
|
|
25
|
+
*
|
|
26
|
+
* // publish the name
|
|
27
|
+
* await name.publish(peerId, cid)
|
|
28
|
+
*
|
|
29
|
+
* // resolve the name
|
|
30
|
+
* const cid = name.resolve(peerId)
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example Using custom PubSub router
|
|
34
|
+
*
|
|
35
|
+
* Additional IPNS routers can be configured - these enable alternative means to
|
|
36
|
+
* publish and resolve IPNS names.
|
|
37
|
+
*
|
|
38
|
+
* One example is the PubSub router - this requires an instance of Helia with
|
|
39
|
+
* libp2p PubSub configured.
|
|
40
|
+
*
|
|
41
|
+
* It works by subscribing to a pubsub topic for each IPNS name that we try to
|
|
42
|
+
* resolve. Updated IPNS records are shared on these topics so an update must
|
|
43
|
+
* occur before the name is resolvable.
|
|
44
|
+
*
|
|
45
|
+
* This router is only suitable for networks where IPNS updates are frequent
|
|
46
|
+
* and multiple peers are listening on the topic(s), otherwise update messages
|
|
47
|
+
* may fail to be published with "Insufficient peers" errors.
|
|
48
|
+
*
|
|
49
|
+
* ```typescript
|
|
50
|
+
* import { createHelia, libp2pDefaults } from 'helia'
|
|
51
|
+
* import { ipns } from '@helia/ipns'
|
|
52
|
+
* import { pubsub } from '@helia/ipns/routing'
|
|
53
|
+
* import { unixfs } from '@helia/unixfs'
|
|
54
|
+
* import { gossipsub } from '@chainsafe/libp2p-gossipsub'
|
|
55
|
+
*
|
|
56
|
+
* const libp2pOptions = libp2pDefaults()
|
|
57
|
+
* libp2pOptions.services.pubsub = gossipsub()
|
|
58
|
+
*
|
|
59
|
+
* const helia = await createHelia({
|
|
60
|
+
* libp2p: libp2pOptions
|
|
61
|
+
* })
|
|
17
62
|
* const name = ipns(helia, {
|
|
18
63
|
* routers: [
|
|
19
|
-
* libp2p(helia),
|
|
20
64
|
* pubsub(helia)
|
|
21
65
|
* ]
|
|
22
66
|
* })
|
|
@@ -121,9 +165,11 @@ import { ipnsValidator } from 'ipns/validator'
|
|
|
121
165
|
import { CID } from 'multiformats/cid'
|
|
122
166
|
import { CustomProgressEvent } from 'progress-events'
|
|
123
167
|
import { defaultResolver } from './dns-resolvers/default.js'
|
|
168
|
+
import { helia } from './routing/helia.js'
|
|
124
169
|
import { localStore, type LocalStore } from './routing/local-store.js'
|
|
125
170
|
import type { IPNSRouting, IPNSRoutingEvents } from './routing/index.js'
|
|
126
171
|
import type { DNSResponse } from './utils/dns.js'
|
|
172
|
+
import type { Routing } from '@helia/interface'
|
|
127
173
|
import type { AbortOptions, PeerId } from '@libp2p/interface'
|
|
128
174
|
import type { Datastore } from 'interface-datastore'
|
|
129
175
|
import type { IPNSRecord } from 'ipns'
|
|
@@ -249,6 +295,7 @@ export type { IPNSRouting } from './routing/index.js'
|
|
|
249
295
|
|
|
250
296
|
export interface IPNSComponents {
|
|
251
297
|
datastore: Datastore
|
|
298
|
+
routing: Routing
|
|
252
299
|
}
|
|
253
300
|
|
|
254
301
|
class DefaultIPNS implements IPNS {
|
|
@@ -258,7 +305,10 @@ class DefaultIPNS implements IPNS {
|
|
|
258
305
|
private readonly defaultResolvers: DNSResolver[]
|
|
259
306
|
|
|
260
307
|
constructor (components: IPNSComponents, routers: IPNSRouting[] = [], resolvers: DNSResolver[] = []) {
|
|
261
|
-
this.routers =
|
|
308
|
+
this.routers = [
|
|
309
|
+
helia(components.routing),
|
|
310
|
+
...routers
|
|
311
|
+
]
|
|
262
312
|
this.localStore = localStore(components.datastore)
|
|
263
313
|
this.defaultResolvers = resolvers.length > 0 ? resolvers : [defaultResolver()]
|
|
264
314
|
}
|
|
@@ -376,21 +426,44 @@ class DefaultIPNS implements IPNS {
|
|
|
376
426
|
}
|
|
377
427
|
|
|
378
428
|
const records: Uint8Array[] = []
|
|
429
|
+
let foundInvalid = 0
|
|
379
430
|
|
|
380
431
|
await Promise.all(
|
|
381
432
|
routers.map(async (router) => {
|
|
433
|
+
let record: Uint8Array
|
|
434
|
+
|
|
435
|
+
try {
|
|
436
|
+
record = await router.get(routingKey, {
|
|
437
|
+
...options,
|
|
438
|
+
validate: false
|
|
439
|
+
})
|
|
440
|
+
} catch (err: any) {
|
|
441
|
+
if (router === this.localStore && err.code === 'ERR_NOT_FOUND') {
|
|
442
|
+
log('did not have record locally')
|
|
443
|
+
} else {
|
|
444
|
+
log.error('error finding IPNS record', err)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return
|
|
448
|
+
}
|
|
449
|
+
|
|
382
450
|
try {
|
|
383
|
-
const record = await router.get(routingKey, options)
|
|
384
451
|
await ipnsValidator(routingKey, record)
|
|
385
452
|
|
|
386
453
|
records.push(record)
|
|
387
454
|
} catch (err) {
|
|
455
|
+
// we found a record, but the validator rejected it
|
|
456
|
+
foundInvalid++
|
|
388
457
|
log.error('error finding IPNS record', err)
|
|
389
458
|
}
|
|
390
459
|
})
|
|
391
460
|
)
|
|
392
461
|
|
|
393
462
|
if (records.length === 0) {
|
|
463
|
+
if (foundInvalid > 0) {
|
|
464
|
+
throw new CodeError(`${foundInvalid > 1 ? `${foundInvalid} records` : 'Record'} found for routing key ${foundInvalid > 1 ? 'were' : 'was'} invalid`, 'ERR_RECORDS_FAILED_VALIDATION')
|
|
465
|
+
}
|
|
466
|
+
|
|
394
467
|
throw new CodeError('Could not find record for routing key', 'ERR_NOT_FOUND')
|
|
395
468
|
}
|
|
396
469
|
|
|
@@ -407,7 +480,7 @@ export interface IPNSOptions {
|
|
|
407
480
|
resolvers?: DNSResolver[]
|
|
408
481
|
}
|
|
409
482
|
|
|
410
|
-
export function ipns (components: IPNSComponents, { routers = [], resolvers = [] }: IPNSOptions): IPNS {
|
|
483
|
+
export function ipns (components: IPNSComponents, { routers = [], resolvers = [] }: IPNSOptions = {}): IPNS {
|
|
411
484
|
return new DefaultIPNS(components, routers, resolvers)
|
|
412
485
|
}
|
|
413
486
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CustomProgressEvent, type ProgressEvent } from 'progress-events'
|
|
2
|
+
import type { GetOptions, PutOptions } from './index.js'
|
|
3
|
+
import type { IPNSRouting } from '../index.js'
|
|
4
|
+
import type { Routing } from '@helia/interface'
|
|
5
|
+
|
|
6
|
+
export interface HeliaRoutingComponents {
|
|
7
|
+
routing: Routing
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type HeliaRoutingProgressEvents =
|
|
11
|
+
ProgressEvent<'ipns:routing:helia:error', Error>
|
|
12
|
+
|
|
13
|
+
export class HeliaRouting implements IPNSRouting {
|
|
14
|
+
private readonly routing: Routing
|
|
15
|
+
|
|
16
|
+
constructor (routing: Routing) {
|
|
17
|
+
this.routing = routing
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async put (routingKey: Uint8Array, marshaledRecord: Uint8Array, options: PutOptions = {}): Promise<void> {
|
|
21
|
+
try {
|
|
22
|
+
await this.routing.put(routingKey, marshaledRecord, options)
|
|
23
|
+
} catch (err: any) {
|
|
24
|
+
options.onProgress?.(new CustomProgressEvent<Error>('ipns:routing:helia:error', err))
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async get (routingKey: Uint8Array, options: GetOptions = {}): Promise<Uint8Array> {
|
|
29
|
+
try {
|
|
30
|
+
return await this.routing.get(routingKey, options)
|
|
31
|
+
} catch (err: any) {
|
|
32
|
+
options.onProgress?.(new CustomProgressEvent<Error>('ipns:routing:helia:error', err))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
throw new Error('Not found')
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The helia routing uses any available Routers configured on the passed Helia
|
|
41
|
+
* node. This could be libp2p, HTTP API Delegated Routing, etc.
|
|
42
|
+
*/
|
|
43
|
+
export function helia (routing: Routing): IPNSRouting {
|
|
44
|
+
return new HeliaRouting(routing)
|
|
45
|
+
}
|
package/src/routing/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { HeliaRoutingProgressEvents } from './helia.js'
|
|
2
2
|
import type { DatastoreProgressEvents } from './local-store.js'
|
|
3
3
|
import type { PubSubProgressEvents } from './pubsub.js'
|
|
4
4
|
import type { AbortOptions } from '@libp2p/interface'
|
|
@@ -9,7 +9,12 @@ export interface PutOptions extends AbortOptions, ProgressOptions {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export interface GetOptions extends AbortOptions, ProgressOptions {
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Pass false to not perform validation actions
|
|
14
|
+
*
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
validate?: boolean
|
|
13
18
|
}
|
|
14
19
|
|
|
15
20
|
export interface IPNSRouting {
|
|
@@ -19,8 +24,8 @@ export interface IPNSRouting {
|
|
|
19
24
|
|
|
20
25
|
export type IPNSRoutingEvents =
|
|
21
26
|
DatastoreProgressEvents |
|
|
22
|
-
|
|
27
|
+
HeliaRoutingProgressEvents |
|
|
23
28
|
PubSubProgressEvents
|
|
24
29
|
|
|
25
|
-
export {
|
|
30
|
+
export { helia } from './helia.js'
|
|
26
31
|
export { pubsub } from './pubsub.js'
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { type ProgressEvent } from 'progress-events';
|
|
2
|
-
import type { GetOptions, PutOptions } from './index.js';
|
|
3
|
-
import type { IPNSRouting } from '../index.js';
|
|
4
|
-
import type { ContentRouting } from '@libp2p/interface';
|
|
5
|
-
export interface Libp2pContentRoutingComponents {
|
|
6
|
-
libp2p: {
|
|
7
|
-
contentRouting: ContentRouting;
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
export type Libp2pContentRoutingProgressEvents = ProgressEvent<'ipns:routing:libp2p:error', Error>;
|
|
11
|
-
export declare class Libp2pContentRouting implements IPNSRouting {
|
|
12
|
-
private readonly contentRouting;
|
|
13
|
-
constructor(components: Libp2pContentRoutingComponents);
|
|
14
|
-
put(routingKey: Uint8Array, marshaledRecord: Uint8Array, options?: PutOptions): Promise<void>;
|
|
15
|
-
get(routingKey: Uint8Array, options?: GetOptions): Promise<Uint8Array>;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* The libp2p routing uses any available Content Routers configured on the
|
|
19
|
-
* passed libp2p node. This could be KadDHT, HTTP API Delegated Routing, etc.
|
|
20
|
-
*/
|
|
21
|
-
export declare function libp2p(components: Libp2pContentRoutingComponents): IPNSRouting;
|
|
22
|
-
//# sourceMappingURL=libp2p.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"libp2p.d.ts","sourceRoot":"","sources":["../../../src/routing/libp2p.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE;QACN,cAAc,EAAE,cAAc,CAAA;KAC/B,CAAA;CACF;AAED,MAAM,MAAM,kCAAkC,GAC5C,aAAa,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAA;AAEnD,qBAAa,oBAAqB,YAAW,WAAW;IACtD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;gBAElC,UAAU,EAAE,8BAA8B;IAIjD,GAAG,CAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAQlG,GAAG,CAAE,UAAU,EAAE,UAAU,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,UAAU,CAAC;CASlF;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAE,UAAU,EAAE,8BAA8B,GAAG,WAAW,CAE/E"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { CustomProgressEvent } from 'progress-events';
|
|
2
|
-
export class Libp2pContentRouting {
|
|
3
|
-
contentRouting;
|
|
4
|
-
constructor(components) {
|
|
5
|
-
this.contentRouting = components.libp2p.contentRouting;
|
|
6
|
-
}
|
|
7
|
-
async put(routingKey, marshaledRecord, options = {}) {
|
|
8
|
-
try {
|
|
9
|
-
await this.contentRouting.put(routingKey, marshaledRecord, options);
|
|
10
|
-
}
|
|
11
|
-
catch (err) {
|
|
12
|
-
options.onProgress?.(new CustomProgressEvent('ipns:routing:libp2p:error', err));
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
async get(routingKey, options = {}) {
|
|
16
|
-
try {
|
|
17
|
-
return await this.contentRouting.get(routingKey, options);
|
|
18
|
-
}
|
|
19
|
-
catch (err) {
|
|
20
|
-
options.onProgress?.(new CustomProgressEvent('ipns:routing:libp2p:error', err));
|
|
21
|
-
}
|
|
22
|
-
throw new Error('Not found');
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* The libp2p routing uses any available Content Routers configured on the
|
|
27
|
-
* passed libp2p node. This could be KadDHT, HTTP API Delegated Routing, etc.
|
|
28
|
-
*/
|
|
29
|
-
export function libp2p(components) {
|
|
30
|
-
return new Libp2pContentRouting(components);
|
|
31
|
-
}
|
|
32
|
-
//# sourceMappingURL=libp2p.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"libp2p.js","sourceRoot":"","sources":["../../../src/routing/libp2p.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAsB,MAAM,iBAAiB,CAAA;AAczE,MAAM,OAAO,oBAAoB;IACd,cAAc,CAAgB;IAE/C,YAAa,UAA0C;QACrD,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,cAAc,CAAA;IACxD,CAAC;IAED,KAAK,CAAC,GAAG,CAAE,UAAsB,EAAE,eAA2B,EAAE,UAAsB,EAAE;QACtF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,eAAe,EAAE,OAAO,CAAC,CAAA;QACrE,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,mBAAmB,CAAQ,2BAA2B,EAAE,GAAG,CAAC,CAAC,CAAA;QACxF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAE,UAAsB,EAAE,UAAsB,EAAE;QACzD,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;QAC3D,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,mBAAmB,CAAQ,2BAA2B,EAAE,GAAG,CAAC,CAAC,CAAA;QACxF,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAA;IAC9B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAE,UAA0C;IAChE,OAAO,IAAI,oBAAoB,CAAC,UAAU,CAAC,CAAA;AAC7C,CAAC"}
|
package/src/routing/libp2p.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { CustomProgressEvent, type ProgressEvent } from 'progress-events'
|
|
2
|
-
import type { GetOptions, PutOptions } from './index.js'
|
|
3
|
-
import type { IPNSRouting } from '../index.js'
|
|
4
|
-
import type { ContentRouting } from '@libp2p/interface'
|
|
5
|
-
|
|
6
|
-
export interface Libp2pContentRoutingComponents {
|
|
7
|
-
libp2p: {
|
|
8
|
-
contentRouting: ContentRouting
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type Libp2pContentRoutingProgressEvents =
|
|
13
|
-
ProgressEvent<'ipns:routing:libp2p:error', Error>
|
|
14
|
-
|
|
15
|
-
export class Libp2pContentRouting implements IPNSRouting {
|
|
16
|
-
private readonly contentRouting: ContentRouting
|
|
17
|
-
|
|
18
|
-
constructor (components: Libp2pContentRoutingComponents) {
|
|
19
|
-
this.contentRouting = components.libp2p.contentRouting
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async put (routingKey: Uint8Array, marshaledRecord: Uint8Array, options: PutOptions = {}): Promise<void> {
|
|
23
|
-
try {
|
|
24
|
-
await this.contentRouting.put(routingKey, marshaledRecord, options)
|
|
25
|
-
} catch (err: any) {
|
|
26
|
-
options.onProgress?.(new CustomProgressEvent<Error>('ipns:routing:libp2p:error', err))
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async get (routingKey: Uint8Array, options: GetOptions = {}): Promise<Uint8Array> {
|
|
31
|
-
try {
|
|
32
|
-
return await this.contentRouting.get(routingKey, options)
|
|
33
|
-
} catch (err: any) {
|
|
34
|
-
options.onProgress?.(new CustomProgressEvent<Error>('ipns:routing:libp2p:error', err))
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
throw new Error('Not found')
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* The libp2p routing uses any available Content Routers configured on the
|
|
43
|
-
* passed libp2p node. This could be KadDHT, HTTP API Delegated Routing, etc.
|
|
44
|
-
*/
|
|
45
|
-
export function libp2p (components: Libp2pContentRoutingComponents): IPNSRouting {
|
|
46
|
-
return new Libp2pContentRouting(components)
|
|
47
|
-
}
|