@helia/ipns 8.2.4 → 9.0.0-4d51f16d
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 +31 -135
- package/dist/index.min.js +11 -11
- package/dist/index.min.js.map +4 -4
- package/dist/src/constants.d.ts +17 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +19 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/errors.d.ts +0 -4
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +0 -7
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +131 -207
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +49 -416
- package/dist/src/index.js.map +1 -1
- package/dist/src/ipns/publisher.d.ts +29 -0
- package/dist/src/ipns/publisher.d.ts.map +1 -0
- package/dist/src/ipns/publisher.js +73 -0
- package/dist/src/ipns/publisher.js.map +1 -0
- package/dist/src/ipns/republisher.d.ts +30 -0
- package/dist/src/ipns/republisher.d.ts.map +1 -0
- package/dist/src/ipns/republisher.js +112 -0
- package/dist/src/ipns/republisher.js.map +1 -0
- package/dist/src/ipns/resolver.d.ts +26 -0
- package/dist/src/ipns/resolver.d.ts.map +1 -0
- package/dist/src/ipns/resolver.js +165 -0
- package/dist/src/ipns/resolver.js.map +1 -0
- package/dist/src/ipns.d.ts +20 -0
- package/dist/src/ipns.d.ts.map +1 -0
- package/dist/src/ipns.js +70 -0
- package/dist/src/ipns.js.map +1 -0
- package/dist/src/local-store.d.ts +42 -0
- package/dist/src/local-store.d.ts.map +1 -0
- package/dist/src/local-store.js +119 -0
- package/dist/src/local-store.js.map +1 -0
- package/dist/src/pb/metadata.d.ts +12 -0
- package/dist/src/pb/metadata.d.ts.map +1 -0
- package/dist/src/pb/metadata.js +57 -0
- package/dist/src/pb/metadata.js.map +1 -0
- package/dist/src/routing/index.d.ts +5 -3
- package/dist/src/routing/index.d.ts.map +1 -1
- package/dist/src/routing/index.js.map +1 -1
- package/dist/src/routing/local-store.d.ts +4 -19
- package/dist/src/routing/local-store.d.ts.map +1 -1
- package/dist/src/routing/local-store.js +7 -62
- package/dist/src/routing/local-store.js.map +1 -1
- package/dist/src/routing/pubsub.d.ts +21 -1
- package/dist/src/routing/pubsub.d.ts.map +1 -1
- package/dist/src/routing/pubsub.js +2 -2
- package/dist/src/routing/pubsub.js.map +1 -1
- package/dist/src/utils.d.ts +24 -0
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +56 -0
- package/dist/src/utils.js.map +1 -1
- package/package.json +21 -23
- package/src/constants.ts +24 -0
- package/src/errors.ts +0 -9
- package/src/index.ts +154 -548
- package/src/ipns/publisher.ts +97 -0
- package/src/ipns/republisher.ts +144 -0
- package/src/ipns/resolver.ts +217 -0
- package/src/ipns.ts +87 -0
- package/src/local-store.ts +162 -0
- package/src/pb/metadata.proto +9 -0
- package/src/pb/metadata.ts +74 -0
- package/src/routing/index.ts +5 -4
- package/src/routing/local-store.ts +9 -87
- package/src/routing/pubsub.ts +28 -4
- package/src/utils.ts +70 -0
- package/dist/src/dnslink.d.ts +0 -9
- package/dist/src/dnslink.d.ts.map +0 -1
- package/dist/src/dnslink.js +0 -138
- package/dist/src/dnslink.js.map +0 -1
- package/dist/typedoc-urls.json +0 -48
- package/src/dnslink.ts +0 -163
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @packageDocumentation
|
|
3
3
|
*
|
|
4
|
-
* IPNS operations using a Helia node
|
|
4
|
+
* [IPNS](https://docs.ipfs.tech/concepts/ipns/) operations using a Helia node
|
|
5
5
|
*
|
|
6
6
|
* @example Getting started
|
|
7
7
|
*
|
|
@@ -11,23 +11,19 @@
|
|
|
11
11
|
* import { createHelia } from 'helia'
|
|
12
12
|
* import { ipns } from '@helia/ipns'
|
|
13
13
|
* import { unixfs } from '@helia/unixfs'
|
|
14
|
-
* import { generateKeyPair } from '@libp2p/crypto/keys'
|
|
15
14
|
*
|
|
16
15
|
* const helia = await createHelia()
|
|
17
16
|
* const name = ipns(helia)
|
|
18
17
|
*
|
|
19
|
-
* // create a keypair to publish an IPNS name
|
|
20
|
-
* const privateKey = await generateKeyPair('Ed25519')
|
|
21
|
-
*
|
|
22
18
|
* // store some data to publish
|
|
23
19
|
* const fs = unixfs(helia)
|
|
24
20
|
* const cid = await fs.addBytes(Uint8Array.from([0, 1, 2, 3, 4]))
|
|
25
21
|
*
|
|
26
22
|
* // publish the name
|
|
27
|
-
* await name.publish(
|
|
23
|
+
* const { publicKey } = await name.publish('key-1', cid)
|
|
28
24
|
*
|
|
29
25
|
* // resolve the name
|
|
30
|
-
* const result = await name.resolve(
|
|
26
|
+
* const result = await name.resolve(publicKey)
|
|
31
27
|
*
|
|
32
28
|
* console.info(result.cid, result.path)
|
|
33
29
|
* ```
|
|
@@ -46,24 +42,18 @@
|
|
|
46
42
|
* const helia = await createHelia()
|
|
47
43
|
* const name = ipns(helia)
|
|
48
44
|
*
|
|
49
|
-
* // create a keypair to publish an IPNS name
|
|
50
|
-
* const privateKey = await generateKeyPair('Ed25519')
|
|
51
|
-
*
|
|
52
45
|
* // store some data to publish
|
|
53
46
|
* const fs = unixfs(helia)
|
|
54
47
|
* const cid = await fs.addBytes(Uint8Array.from([0, 1, 2, 3, 4]))
|
|
55
48
|
*
|
|
56
49
|
* // publish the name
|
|
57
|
-
* await name.publish(
|
|
58
|
-
*
|
|
59
|
-
* // create another keypair to re-publish the original record
|
|
60
|
-
* const recursivePrivateKey = await generateKeyPair('Ed25519')
|
|
50
|
+
* const { publicKey } = await name.publish('key-1', cid)
|
|
61
51
|
*
|
|
62
52
|
* // publish the recursive name
|
|
63
|
-
* await name.publish(
|
|
53
|
+
* const { publicKey: recursivePublicKey } = await name.publish('key-2', publicKey)
|
|
64
54
|
*
|
|
65
55
|
* // resolve the name recursively - it resolves until a CID is found
|
|
66
|
-
* const result = await name.resolve(
|
|
56
|
+
* const result = await name.resolve(recursivePublicKey)
|
|
67
57
|
* console.info(result.cid.toString() === cid.toString()) // true
|
|
68
58
|
* ```
|
|
69
59
|
*
|
|
@@ -80,9 +70,6 @@
|
|
|
80
70
|
* const helia = await createHelia()
|
|
81
71
|
* const name = ipns(helia)
|
|
82
72
|
*
|
|
83
|
-
* // create a keypair to publish an IPNS name
|
|
84
|
-
* const privateKey = await generateKeyPair('Ed25519')
|
|
85
|
-
*
|
|
86
73
|
* // store some data to publish
|
|
87
74
|
* const fs = unixfs(helia)
|
|
88
75
|
* const fileCid = await fs.addBytes(Uint8Array.from([0, 1, 2, 3, 4]))
|
|
@@ -92,10 +79,10 @@
|
|
|
92
79
|
* const finalDirCid = await fs.cp(fileCid, dirCid, '/foo.txt')
|
|
93
80
|
*
|
|
94
81
|
* // publish the name
|
|
95
|
-
* await name.publish(
|
|
82
|
+
* const { publicKey } = await name.publish('key-1', `/ipfs/${finalDirCid}/foo.txt`)
|
|
96
83
|
*
|
|
97
84
|
* // resolve the name
|
|
98
|
-
* const result = await name.resolve(
|
|
85
|
+
* const result = await name.resolve(publicKey)
|
|
99
86
|
*
|
|
100
87
|
* console.info(result.cid, result.path) // QmFoo.. 'foo.txt'
|
|
101
88
|
* ```
|
|
@@ -121,13 +108,14 @@
|
|
|
121
108
|
* import { ipns } from '@helia/ipns'
|
|
122
109
|
* import { pubsub } from '@helia/ipns/routing'
|
|
123
110
|
* import { unixfs } from '@helia/unixfs'
|
|
124
|
-
* import {
|
|
111
|
+
* import { floodsub } from '@libp2p/floodsub'
|
|
125
112
|
* import { generateKeyPair } from '@libp2p/crypto/keys'
|
|
126
|
-
* import type {
|
|
113
|
+
* import type { PubSub } from '@helia/ipns/routing'
|
|
114
|
+
* import type { Libp2p } from '@libp2p/interface'
|
|
127
115
|
* import type { DefaultLibp2pServices } from 'helia'
|
|
128
116
|
*
|
|
129
117
|
* const libp2pOptions = libp2pDefaults()
|
|
130
|
-
* libp2pOptions.services.pubsub =
|
|
118
|
+
* libp2pOptions.services.pubsub = floodsub()
|
|
131
119
|
*
|
|
132
120
|
* const helia = await createHelia<Libp2p<DefaultLibp2pServices & { pubsub: PubSub }>>({
|
|
133
121
|
* libp2p: libp2pOptions
|
|
@@ -138,133 +126,30 @@
|
|
|
138
126
|
* ]
|
|
139
127
|
* })
|
|
140
128
|
*
|
|
141
|
-
* // create a keypair to publish an IPNS name
|
|
142
|
-
* const privateKey = await generateKeyPair('Ed25519')
|
|
143
129
|
*
|
|
144
130
|
* // store some data to publish
|
|
145
131
|
* const fs = unixfs(helia)
|
|
146
132
|
* const cid = await fs.addBytes(Uint8Array.from([0, 1, 2, 3, 4]))
|
|
147
133
|
*
|
|
148
134
|
* // publish the name
|
|
149
|
-
* await name.publish(
|
|
135
|
+
* const { publicKey } = await name.publish('key-1', cid)
|
|
150
136
|
*
|
|
151
137
|
* // resolve the name
|
|
152
|
-
* const result = await name.resolve(
|
|
153
|
-
* ```
|
|
154
|
-
*
|
|
155
|
-
* @example Using custom DNS over HTTPS resolvers
|
|
156
|
-
*
|
|
157
|
-
* To use custom resolvers, configure Helia's `dns` option:
|
|
158
|
-
*
|
|
159
|
-
* ```TypeScript
|
|
160
|
-
* import { createHelia } from 'helia'
|
|
161
|
-
* import { ipns } from '@helia/ipns'
|
|
162
|
-
* import { dns } from '@multiformats/dns'
|
|
163
|
-
* import { dnsOverHttps } from '@multiformats/dns/resolvers'
|
|
164
|
-
* import { helia } from '@helia/ipns/routing'
|
|
165
|
-
*
|
|
166
|
-
* const node = await createHelia({
|
|
167
|
-
* dns: dns({
|
|
168
|
-
* resolvers: {
|
|
169
|
-
* '.': dnsOverHttps('https://private-dns-server.me/dns-query')
|
|
170
|
-
* }
|
|
171
|
-
* })
|
|
172
|
-
* })
|
|
173
|
-
* const name = ipns(node, {
|
|
174
|
-
* routers: [
|
|
175
|
-
* helia(node.routing)
|
|
176
|
-
* ]
|
|
177
|
-
* })
|
|
178
|
-
*
|
|
179
|
-
* const result = name.resolveDNSLink('some-domain-with-dnslink-entry.com')
|
|
180
|
-
* ```
|
|
181
|
-
*
|
|
182
|
-
* @example Resolving a domain with a dnslink entry
|
|
183
|
-
*
|
|
184
|
-
* Calling `resolveDNSLink` with the `@helia/ipns` instance:
|
|
185
|
-
*
|
|
186
|
-
* ```TypeScript
|
|
187
|
-
* // resolve a CID from a TXT record in a DNS zone file, using the default
|
|
188
|
-
* // resolver for the current platform eg:
|
|
189
|
-
* // > dig _dnslink.ipfs.io TXT
|
|
190
|
-
* // ;; ANSWER SECTION:
|
|
191
|
-
* // _dnslink.ipfs.io. 60 IN TXT "dnslink=/ipns/website.ipfs.io"
|
|
192
|
-
* // > dig _dnslink.website.ipfs.io TXT
|
|
193
|
-
* // ;; ANSWER SECTION:
|
|
194
|
-
* // _dnslink.website.ipfs.io. 60 IN TXT "dnslink=/ipfs/QmWebsite"
|
|
195
|
-
*
|
|
196
|
-
* import { createHelia } from 'helia'
|
|
197
|
-
* import { ipns } from '@helia/ipns'
|
|
198
|
-
*
|
|
199
|
-
* const node = await createHelia()
|
|
200
|
-
* const name = ipns(node)
|
|
201
|
-
*
|
|
202
|
-
* const { answer } = await name.resolveDNSLink('ipfs.io')
|
|
203
|
-
*
|
|
204
|
-
* console.info(answer)
|
|
205
|
-
* // { data: '/ipfs/QmWebsite' }
|
|
206
|
-
* ```
|
|
207
|
-
*
|
|
208
|
-
* @example Using DNS-Over-HTTPS
|
|
209
|
-
*
|
|
210
|
-
* This example uses the Mozilla provided RFC 1035 DNS over HTTPS service. This
|
|
211
|
-
* uses binary DNS records so requires extra dependencies to process the
|
|
212
|
-
* response which can increase browser bundle sizes.
|
|
213
|
-
*
|
|
214
|
-
* If this is a concern, use the DNS-JSON-Over-HTTPS resolver instead.
|
|
215
|
-
*
|
|
216
|
-
* ```TypeScript
|
|
217
|
-
* import { createHelia } from 'helia'
|
|
218
|
-
* import { ipns } from '@helia/ipns'
|
|
219
|
-
* import { dns } from '@multiformats/dns'
|
|
220
|
-
* import { dnsOverHttps } from '@multiformats/dns/resolvers'
|
|
221
|
-
*
|
|
222
|
-
* const node = await createHelia({
|
|
223
|
-
* dns: dns({
|
|
224
|
-
* resolvers: {
|
|
225
|
-
* '.': dnsOverHttps('https://mozilla.cloudflare-dns.com/dns-query')
|
|
226
|
-
* }
|
|
227
|
-
* })
|
|
228
|
-
* })
|
|
229
|
-
* const name = ipns(node)
|
|
230
|
-
*
|
|
231
|
-
* const result = await name.resolveDNSLink('ipfs.io')
|
|
232
|
-
* ```
|
|
233
|
-
*
|
|
234
|
-
* @example Using DNS-JSON-Over-HTTPS
|
|
235
|
-
*
|
|
236
|
-
* DNS-JSON-Over-HTTPS resolvers use the RFC 8427 `application/dns-json` and can
|
|
237
|
-
* result in a smaller browser bundle due to the response being plain JSON.
|
|
238
|
-
*
|
|
239
|
-
* ```TypeScript
|
|
240
|
-
* import { createHelia } from 'helia'
|
|
241
|
-
* import { ipns } from '@helia/ipns'
|
|
242
|
-
* import { dns } from '@multiformats/dns'
|
|
243
|
-
* import { dnsJsonOverHttps } from '@multiformats/dns/resolvers'
|
|
244
|
-
*
|
|
245
|
-
* const node = await createHelia({
|
|
246
|
-
* dns: dns({
|
|
247
|
-
* resolvers: {
|
|
248
|
-
* '.': dnsJsonOverHttps('https://mozilla.cloudflare-dns.com/dns-query')
|
|
249
|
-
* }
|
|
250
|
-
* })
|
|
251
|
-
* })
|
|
252
|
-
* const name = ipns(node)
|
|
253
|
-
*
|
|
254
|
-
* const result = await name.resolveDNSLink('ipfs.io')
|
|
138
|
+
* const result = await name.resolve(publicKey)
|
|
255
139
|
* ```
|
|
256
140
|
*
|
|
257
141
|
* @example Republishing an existing IPNS record
|
|
258
142
|
*
|
|
259
|
-
*
|
|
260
|
-
* needing the private key. This
|
|
261
|
-
*
|
|
143
|
+
* It is sometimes useful to be able to republish an existing IPNS record
|
|
144
|
+
* without needing the private key. This allows you to extend the availability
|
|
145
|
+
* of a record that was created elsewhere.
|
|
262
146
|
*
|
|
263
147
|
* ```TypeScript
|
|
264
148
|
* import { createHelia } from 'helia'
|
|
265
|
-
* import { ipns } from '@helia/ipns'
|
|
149
|
+
* import { ipns, ipnsValidator } from '@helia/ipns'
|
|
266
150
|
* import { createDelegatedRoutingV1HttpApiClient } from '@helia/delegated-routing-v1-http-api-client'
|
|
267
151
|
* import { CID } from 'multiformats/cid'
|
|
152
|
+
* import { multihashToIPNSRoutingKey, marshalIPNSRecord } from 'ipns'
|
|
268
153
|
*
|
|
269
154
|
* const helia = await createHelia()
|
|
270
155
|
* const name = ipns(helia)
|
|
@@ -274,47 +159,38 @@
|
|
|
274
159
|
* const delegatedClient = createDelegatedRoutingV1HttpApiClient('https://delegated-ipfs.dev')
|
|
275
160
|
* const record = await delegatedClient.getIPNS(parsedCid)
|
|
276
161
|
*
|
|
277
|
-
*
|
|
162
|
+
* const routingKey = multihashToIPNSRoutingKey(parsedCid.multihash)
|
|
163
|
+
* const marshaledRecord = marshalIPNSRecord(record)
|
|
164
|
+
*
|
|
165
|
+
* // validate that they key corresponds to the record
|
|
166
|
+
* await ipnsValidator(routingKey, marshaledRecord)
|
|
167
|
+
*
|
|
168
|
+
* // publish record to routing
|
|
169
|
+
* await Promise.all(
|
|
170
|
+
* name.routers.map(async r => {
|
|
171
|
+
* await r.put(routingKey, marshaledRecord)
|
|
172
|
+
* })
|
|
173
|
+
* )
|
|
278
174
|
* ```
|
|
279
175
|
*/
|
|
280
176
|
|
|
281
|
-
import { NotFoundError, isPublicKey } from '@libp2p/interface'
|
|
282
|
-
import { logger } from '@libp2p/logger'
|
|
283
|
-
import { peerIdFromString } from '@libp2p/peer-id'
|
|
284
|
-
import { createIPNSRecord, extractPublicKeyFromIPNSRecord, marshalIPNSRecord, multihashToIPNSRoutingKey, unmarshalIPNSRecord } from 'ipns'
|
|
285
|
-
import { ipnsSelector } from 'ipns/selector'
|
|
286
177
|
import { ipnsValidator } from 'ipns/validator'
|
|
287
|
-
import { base36 } from 'multiformats/bases/base36'
|
|
288
|
-
import { base58btc } from 'multiformats/bases/base58'
|
|
289
178
|
import { CID } from 'multiformats/cid'
|
|
290
|
-
import
|
|
291
|
-
import {
|
|
292
|
-
import {
|
|
293
|
-
import {
|
|
294
|
-
import {
|
|
295
|
-
import {
|
|
296
|
-
import {
|
|
297
|
-
import type {
|
|
298
|
-
import type {
|
|
299
|
-
import type {
|
|
300
|
-
import type { AbortOptions, ComponentLogger, Logger, PrivateKey, PublicKey } from '@libp2p/interface'
|
|
301
|
-
import type { Answer, DNS, ResolveDnsProgressEvents } from '@multiformats/dns'
|
|
179
|
+
import { IPNSResolver as IPNSResolverClass } from './ipns/resolver.js'
|
|
180
|
+
import { IPNS as IPNSClass } from './ipns.js'
|
|
181
|
+
import { localStore } from './local-store.ts'
|
|
182
|
+
import { helia } from './routing/index.js'
|
|
183
|
+
import { localStoreRouting } from './routing/local-store.ts'
|
|
184
|
+
import type { IPNSResolverComponents } from './ipns/resolver.js'
|
|
185
|
+
import type { IPNSRouting, IPNSRoutingProgressEvents } from './routing/index.js'
|
|
186
|
+
import type { Routing, HeliaEvents } from '@helia/interface'
|
|
187
|
+
import type { AbortOptions, ComponentLogger, Libp2p, PeerId, PublicKey, TypedEventEmitter } from '@libp2p/interface'
|
|
188
|
+
import type { Keychain } from '@libp2p/keychain'
|
|
302
189
|
import type { Datastore } from 'interface-datastore'
|
|
303
190
|
import type { IPNSRecord } from 'ipns'
|
|
304
|
-
import type { MultibaseDecoder } from 'multiformats/bases/interface'
|
|
305
191
|
import type { MultihashDigest } from 'multiformats/hashes/interface'
|
|
306
192
|
import type { ProgressEvent, ProgressOptions } from 'progress-events'
|
|
307
193
|
|
|
308
|
-
const log = logger('helia:ipns')
|
|
309
|
-
|
|
310
|
-
const MINUTE = 60 * 1000
|
|
311
|
-
const HOUR = 60 * MINUTE
|
|
312
|
-
|
|
313
|
-
const DEFAULT_LIFETIME_MS = 48 * HOUR
|
|
314
|
-
const DEFAULT_REPUBLISH_INTERVAL_MS = 23 * HOUR
|
|
315
|
-
|
|
316
|
-
const DEFAULT_TTL_NS = BigInt(MINUTE) * 5_000_000n // 5 minutes
|
|
317
|
-
|
|
318
194
|
export type PublishProgressEvents =
|
|
319
195
|
ProgressEvent<'ipns:publish:start'> |
|
|
320
196
|
ProgressEvent<'ipns:publish:success', IPNSRecord> |
|
|
@@ -325,17 +201,13 @@ export type ResolveProgressEvents =
|
|
|
325
201
|
ProgressEvent<'ipns:resolve:success', IPNSRecord> |
|
|
326
202
|
ProgressEvent<'ipns:resolve:error', Error>
|
|
327
203
|
|
|
328
|
-
export type
|
|
329
|
-
ProgressEvent<'ipns:
|
|
330
|
-
ProgressEvent<'ipns:
|
|
331
|
-
ProgressEvent<'ipns:
|
|
332
|
-
|
|
333
|
-
export type ResolveDNSLinkProgressEvents =
|
|
334
|
-
ResolveProgressEvents |
|
|
335
|
-
IPNSRoutingEvents |
|
|
336
|
-
ResolveDnsProgressEvents
|
|
204
|
+
export type DatastoreProgressEvents =
|
|
205
|
+
ProgressEvent<'ipns:routing:datastore:put'> |
|
|
206
|
+
ProgressEvent<'ipns:routing:datastore:get'> |
|
|
207
|
+
ProgressEvent<'ipns:routing:datastore:list'> |
|
|
208
|
+
ProgressEvent<'ipns:routing:datastore:error', Error>
|
|
337
209
|
|
|
338
|
-
export interface PublishOptions extends AbortOptions, ProgressOptions<PublishProgressEvents |
|
|
210
|
+
export interface PublishOptions extends AbortOptions, ProgressOptions<PublishProgressEvents | IPNSRoutingProgressEvents> {
|
|
339
211
|
/**
|
|
340
212
|
* Time duration of the signature validity in ms (default: 48hrs)
|
|
341
213
|
*/
|
|
@@ -358,23 +230,12 @@ export interface PublishOptions extends AbortOptions, ProgressOptions<PublishPro
|
|
|
358
230
|
ttl?: number
|
|
359
231
|
}
|
|
360
232
|
|
|
361
|
-
export interface
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
*
|
|
365
|
-
* @default false
|
|
366
|
-
*/
|
|
367
|
-
offline?: boolean
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Do not use cached IPNS Record entries
|
|
371
|
-
*
|
|
372
|
-
* @default false
|
|
373
|
-
*/
|
|
374
|
-
nocache?: boolean
|
|
233
|
+
export interface IPNSRecordMetadata {
|
|
234
|
+
keyName: string
|
|
235
|
+
lifetime: number
|
|
375
236
|
}
|
|
376
237
|
|
|
377
|
-
export interface
|
|
238
|
+
export interface ResolveOptions extends AbortOptions, ProgressOptions<ResolveProgressEvents | IPNSRoutingProgressEvents> {
|
|
378
239
|
/**
|
|
379
240
|
* Do not query the network for the IPNS record
|
|
380
241
|
*
|
|
@@ -383,35 +244,11 @@ export interface ResolveDNSLinkOptions extends AbortOptions, ProgressOptions<Res
|
|
|
383
244
|
offline?: boolean
|
|
384
245
|
|
|
385
246
|
/**
|
|
386
|
-
* Do not use cached
|
|
247
|
+
* Do not use cached IPNS Record entries
|
|
387
248
|
*
|
|
388
249
|
* @default false
|
|
389
250
|
*/
|
|
390
251
|
nocache?: boolean
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* When resolving DNSLink records that resolve to other DNSLink records, limit
|
|
394
|
-
* how many times we will recursively resolve them.
|
|
395
|
-
*
|
|
396
|
-
* @default 32
|
|
397
|
-
*/
|
|
398
|
-
maxRecursiveDepth?: number
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
export interface RepublishOptions extends AbortOptions, ProgressOptions<RepublishProgressEvents | IPNSRoutingEvents> {
|
|
402
|
-
/**
|
|
403
|
-
* The republish interval in ms (default: 23hrs)
|
|
404
|
-
*/
|
|
405
|
-
interval?: number
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
export interface RepublishRecordOptions extends AbortOptions, ProgressOptions<RepublishProgressEvents | IPNSRoutingEvents> {
|
|
409
|
-
/**
|
|
410
|
-
* Only publish to a local datastore
|
|
411
|
-
*
|
|
412
|
-
* @default false
|
|
413
|
-
*/
|
|
414
|
-
offline?: boolean
|
|
415
252
|
}
|
|
416
253
|
|
|
417
254
|
export interface ResolveResult {
|
|
@@ -422,10 +259,8 @@ export interface ResolveResult {
|
|
|
422
259
|
|
|
423
260
|
/**
|
|
424
261
|
* Any path component that was part of the resolved record
|
|
425
|
-
*
|
|
426
|
-
* @default ""
|
|
427
262
|
*/
|
|
428
|
-
path
|
|
263
|
+
path?: string
|
|
429
264
|
}
|
|
430
265
|
|
|
431
266
|
export interface IPNSResolveResult extends ResolveResult {
|
|
@@ -435,44 +270,84 @@ export interface IPNSResolveResult extends ResolveResult {
|
|
|
435
270
|
record: IPNSRecord
|
|
436
271
|
}
|
|
437
272
|
|
|
438
|
-
export interface
|
|
273
|
+
export interface IPNSPublishResult {
|
|
439
274
|
/**
|
|
440
|
-
* The
|
|
275
|
+
* The published record
|
|
441
276
|
*/
|
|
442
|
-
|
|
277
|
+
record: IPNSRecord
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* The public key that was used to publish the record
|
|
281
|
+
*/
|
|
282
|
+
publicKey: PublicKey
|
|
443
283
|
}
|
|
444
284
|
|
|
445
|
-
export interface
|
|
285
|
+
export interface IPNSResolver {
|
|
446
286
|
/**
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
287
|
+
* Accepts a libp2p public key, a CID with the libp2p-key codec and either the
|
|
288
|
+
* identity hash (for Ed25519 and secp256k1 public keys) or a SHA256 hash (for
|
|
289
|
+
* RSA public keys), or the multihash of a libp2p-key encoded CID, or a
|
|
290
|
+
* Ed25519, secp256k1 or RSA PeerId and recursively resolves the IPNS record
|
|
291
|
+
* corresponding to that key until a value is found.
|
|
450
292
|
*/
|
|
451
|
-
|
|
293
|
+
resolve(key: CID<unknown, 0x72, 0x00 | 0x12, 1> | PublicKey | MultihashDigest<0x00 | 0x12> | PeerId, options?: ResolveOptions): Promise<IPNSResolveResult>
|
|
294
|
+
}
|
|
452
295
|
|
|
296
|
+
export interface IPNS {
|
|
453
297
|
/**
|
|
454
|
-
*
|
|
455
|
-
* corresponding to that public key until a value is found
|
|
298
|
+
* Configured routing subsystems used to publish/resolve IPNS names
|
|
456
299
|
*/
|
|
457
|
-
|
|
300
|
+
routers: IPNSRouting[]
|
|
458
301
|
|
|
459
302
|
/**
|
|
460
|
-
*
|
|
303
|
+
* Creates and publishes an IPNS record that will resolve the passed value
|
|
304
|
+
* signed by a key stored in the libp2p keychain under the passed key name.
|
|
305
|
+
*
|
|
306
|
+
* It is possible to create a recursive IPNS record by passing:
|
|
307
|
+
*
|
|
308
|
+
* - A PeerId,
|
|
309
|
+
* - A PublicKey
|
|
310
|
+
* - A CID with the libp2p-key codec and Identity or SHA256 hash algorithms
|
|
311
|
+
* - A Multihash with the Identity or SHA256 hash algorithms
|
|
312
|
+
* - A string IPNS key (e.g. `/ipns/Qmfoo`)
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
*
|
|
316
|
+
* ```TypeScript
|
|
317
|
+
* import { createHelia } from 'helia'
|
|
318
|
+
* import { ipns } from '@helia/ipns'
|
|
319
|
+
*
|
|
320
|
+
* const helia = await createHelia()
|
|
321
|
+
* const name = ipns(helia)
|
|
322
|
+
*
|
|
323
|
+
* const result = await name.publish('my-key-name', cid, {
|
|
324
|
+
* signal: AbortSignal.timeout(5_000)
|
|
325
|
+
* })
|
|
326
|
+
*
|
|
327
|
+
* console.info(result) // { answer: ... }
|
|
328
|
+
* ```
|
|
461
329
|
*/
|
|
462
|
-
|
|
330
|
+
publish(keyName: string, value: CID | PublicKey | MultihashDigest<0x00 | 0x12> | PeerId | string, options?: PublishOptions): Promise<IPNSPublishResult>
|
|
463
331
|
|
|
464
332
|
/**
|
|
465
|
-
*
|
|
333
|
+
* Accepts a libp2p public key, a CID with the libp2p-key codec and either the
|
|
334
|
+
* identity hash (for Ed25519 and secp256k1 public keys) or a SHA256 hash (for
|
|
335
|
+
* RSA public keys), or the multihash of a libp2p-key encoded CID, or a
|
|
336
|
+
* Ed25519, secp256k1 or RSA PeerId and recursively resolves the IPNS record
|
|
337
|
+
* corresponding to that key until a value is found.
|
|
466
338
|
*/
|
|
467
|
-
|
|
339
|
+
resolve(key: CID<unknown, 0x72, 0x00 | 0x12, 1> | PublicKey | MultihashDigest<0x00 | 0x12> | PeerId, options?: ResolveOptions): Promise<IPNSResolveResult>
|
|
468
340
|
|
|
469
341
|
/**
|
|
470
|
-
*
|
|
342
|
+
* Stop republishing of an IPNS record
|
|
471
343
|
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
344
|
+
* This will delete the last signed IPNS record from the datastore, but the
|
|
345
|
+
* key will remain in the keychain.
|
|
346
|
+
*
|
|
347
|
+
* Note that the record may still be resolved by other peers until it expires
|
|
348
|
+
* or is no longer valid.
|
|
474
349
|
*/
|
|
475
|
-
|
|
350
|
+
unpublish(keyName: string, options?: AbortOptions): Promise<void>
|
|
476
351
|
}
|
|
477
352
|
|
|
478
353
|
export type { IPNSRouting } from './routing/index.js'
|
|
@@ -482,326 +357,57 @@ export type { IPNSRecord } from 'ipns'
|
|
|
482
357
|
export interface IPNSComponents {
|
|
483
358
|
datastore: Datastore
|
|
484
359
|
routing: Routing
|
|
485
|
-
dns: DNS
|
|
486
360
|
logger: ComponentLogger
|
|
361
|
+
libp2p: Libp2p<{ keychain: Keychain }>
|
|
362
|
+
events: TypedEventEmitter<HeliaEvents> // Helia event bus
|
|
487
363
|
}
|
|
488
364
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
365
|
+
export interface IPNSOptions {
|
|
366
|
+
/**
|
|
367
|
+
* Different routing systems for IPNS publishing/resolving
|
|
368
|
+
*/
|
|
369
|
+
routers?: IPNSRouting[]
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* How often to check if published records have expired and need republishing
|
|
373
|
+
* in ms
|
|
374
|
+
*
|
|
375
|
+
* @default 3_600_000
|
|
376
|
+
*/
|
|
377
|
+
republishInterval?: number
|
|
493
378
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
constructor (components: IPNSComponents, routers: IPNSRouting[] = []) {
|
|
502
|
-
this.routers = [
|
|
503
|
-
helia(components.routing),
|
|
504
|
-
...routers
|
|
505
|
-
]
|
|
506
|
-
this.localStore = localStore(components.datastore)
|
|
507
|
-
this.dns = components.dns
|
|
508
|
-
this.log = components.logger.forComponent('helia:ipns')
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
async publish (key: PrivateKey, value: CID | PublicKey | MultihashDigest<0x00 | 0x12> | string, options: PublishOptions = {}): Promise<IPNSRecord> {
|
|
512
|
-
try {
|
|
513
|
-
let sequenceNumber = 1n
|
|
514
|
-
const routingKey = multihashToIPNSRoutingKey(key.publicKey.toMultihash())
|
|
515
|
-
|
|
516
|
-
if (await this.localStore.has(routingKey, options)) {
|
|
517
|
-
// if we have published under this key before, increment the sequence number
|
|
518
|
-
const { record } = await this.localStore.get(routingKey, options)
|
|
519
|
-
const existingRecord = unmarshalIPNSRecord(record)
|
|
520
|
-
sequenceNumber = existingRecord.sequence + 1n
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
// convert ttl from milliseconds to nanoseconds as createIPNSRecord expects
|
|
524
|
-
const ttlNs = options.ttl != null ? BigInt(options.ttl) * 1_000_000n : DEFAULT_TTL_NS
|
|
525
|
-
const record = await createIPNSRecord(key, value, sequenceNumber, options.lifetime ?? DEFAULT_LIFETIME_MS, { ...options, ttlNs })
|
|
526
|
-
const marshaledRecord = marshalIPNSRecord(record)
|
|
527
|
-
|
|
528
|
-
await this.localStore.put(routingKey, marshaledRecord, options)
|
|
529
|
-
|
|
530
|
-
if (options.offline !== true) {
|
|
531
|
-
// publish record to routing
|
|
532
|
-
await Promise.all(this.routers.map(async r => { await r.put(routingKey, marshaledRecord, options) }))
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
return record
|
|
536
|
-
} catch (err: any) {
|
|
537
|
-
options.onProgress?.(new CustomProgressEvent<Error>('ipns:publish:error', err))
|
|
538
|
-
throw err
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
async resolve (key: PublicKey | MultihashDigest<0x00 | 0x12>, options: ResolveOptions = {}): Promise<IPNSResolveResult> {
|
|
543
|
-
const digest = isPublicKey(key) ? key.toMultihash() : key
|
|
544
|
-
const routingKey = multihashToIPNSRoutingKey(digest)
|
|
545
|
-
const record = await this.#findIpnsRecord(routingKey, options)
|
|
546
|
-
|
|
547
|
-
return {
|
|
548
|
-
...(await this.#resolve(record.value, options)),
|
|
549
|
-
record
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
async resolveDNSLink (domain: string, options: ResolveDNSLinkOptions = {}): Promise<DNSLinkResolveResult> {
|
|
554
|
-
const dnslink = await resolveDNSLink(domain, this.dns, this.log, options)
|
|
555
|
-
|
|
556
|
-
return {
|
|
557
|
-
...(await this.#resolve(dnslink.value, options)),
|
|
558
|
-
answer: dnslink.answer
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
republish (options: RepublishOptions = {}): void {
|
|
563
|
-
if (this.timeout != null) {
|
|
564
|
-
throw new Error('Republish is already running')
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
options.signal?.addEventListener('abort', () => {
|
|
568
|
-
clearTimeout(this.timeout)
|
|
569
|
-
})
|
|
570
|
-
|
|
571
|
-
async function republish (): Promise<void> {
|
|
572
|
-
const startTime = Date.now()
|
|
573
|
-
|
|
574
|
-
options.onProgress?.(new CustomProgressEvent('ipns:republish:start'))
|
|
575
|
-
|
|
576
|
-
const finishType = Date.now()
|
|
577
|
-
const timeTaken = finishType - startTime
|
|
578
|
-
let nextInterval = DEFAULT_REPUBLISH_INTERVAL_MS - timeTaken
|
|
579
|
-
|
|
580
|
-
if (nextInterval < 0) {
|
|
581
|
-
nextInterval = options.interval ?? DEFAULT_REPUBLISH_INTERVAL_MS
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
setTimeout(() => {
|
|
585
|
-
republish().catch(err => {
|
|
586
|
-
log.error('error republishing', err)
|
|
587
|
-
})
|
|
588
|
-
}, nextInterval)
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
this.timeout = setTimeout(() => {
|
|
592
|
-
republish().catch(err => {
|
|
593
|
-
log.error('error republishing', err)
|
|
594
|
-
})
|
|
595
|
-
}, options.interval ?? DEFAULT_REPUBLISH_INTERVAL_MS)
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
async #resolve (ipfsPath: string, options: ResolveOptions = {}): Promise<{ cid: CID, path: string }> {
|
|
599
|
-
const parts = ipfsPath.split('/')
|
|
600
|
-
try {
|
|
601
|
-
const scheme = parts[1]
|
|
602
|
-
|
|
603
|
-
if (scheme === 'ipns') {
|
|
604
|
-
const str = parts[2]
|
|
605
|
-
const prefix = str.substring(0, 1)
|
|
606
|
-
let buf: Uint8Array | undefined
|
|
607
|
-
|
|
608
|
-
if (prefix === '1' || prefix === 'Q') {
|
|
609
|
-
buf = base58btc.decode(`z${str}`)
|
|
610
|
-
} else if (bases[prefix] != null) {
|
|
611
|
-
buf = bases[prefix].decode(str)
|
|
612
|
-
} else {
|
|
613
|
-
throw new UnsupportedMultibasePrefixError(`Unsupported multibase prefix "${prefix}"`)
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
let digest: MultihashDigest<number>
|
|
617
|
-
|
|
618
|
-
try {
|
|
619
|
-
digest = Digest.decode(buf)
|
|
620
|
-
} catch {
|
|
621
|
-
digest = CID.decode(buf).multihash
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
if (!isCodec(digest, IDENTITY_CODEC) && !isCodec(digest, SHA2_256_CODEC)) {
|
|
625
|
-
throw new UnsupportedMultihashCodecError(`Unsupported multihash codec "${digest.code}"`)
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
const { cid } = await this.resolve(digest, options)
|
|
629
|
-
const path = parts.slice(3).join('/')
|
|
630
|
-
return {
|
|
631
|
-
cid,
|
|
632
|
-
path
|
|
633
|
-
}
|
|
634
|
-
} else if (scheme === 'ipfs') {
|
|
635
|
-
const cid = CID.parse(parts[2])
|
|
636
|
-
const path = parts.slice(3).join('/')
|
|
637
|
-
return {
|
|
638
|
-
cid,
|
|
639
|
-
path
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
} catch (err) {
|
|
643
|
-
log.error('error parsing ipfs path', err)
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
log.error('invalid ipfs path %s', ipfsPath)
|
|
647
|
-
throw new InvalidValueError('Invalid value')
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
async #findIpnsRecord (routingKey: Uint8Array, options: ResolveOptions = {}): Promise<IPNSRecord> {
|
|
651
|
-
const records: Uint8Array[] = []
|
|
652
|
-
const cached = await this.localStore.has(routingKey, options)
|
|
653
|
-
|
|
654
|
-
if (cached) {
|
|
655
|
-
log('record is present in the cache')
|
|
656
|
-
|
|
657
|
-
if (options.nocache !== true) {
|
|
658
|
-
try {
|
|
659
|
-
// check the local cache first
|
|
660
|
-
const { record, created } = await this.localStore.get(routingKey, options)
|
|
661
|
-
|
|
662
|
-
this.log('record retrieved from cache')
|
|
663
|
-
|
|
664
|
-
// validate the record
|
|
665
|
-
await ipnsValidator(routingKey, record)
|
|
666
|
-
|
|
667
|
-
this.log('record was valid')
|
|
668
|
-
|
|
669
|
-
// check the TTL
|
|
670
|
-
const ipnsRecord = unmarshalIPNSRecord(record)
|
|
671
|
-
|
|
672
|
-
// IPNS TTL is in nanoseconds, convert to milliseconds, default to one
|
|
673
|
-
// hour
|
|
674
|
-
const ttlMs = Number((ipnsRecord.ttl ?? DEFAULT_TTL_NS) / 1_000_000n)
|
|
675
|
-
const ttlExpires = created.getTime() + ttlMs
|
|
676
|
-
|
|
677
|
-
if (ttlExpires > Date.now()) {
|
|
678
|
-
// the TTL has not yet expired, return the cached record
|
|
679
|
-
this.log('record TTL was valid')
|
|
680
|
-
return ipnsRecord
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
if (options.offline === true) {
|
|
684
|
-
// the TTL has expired but we are skipping the routing search
|
|
685
|
-
this.log('record TTL has been reached but we are resolving offline-only, returning record')
|
|
686
|
-
return ipnsRecord
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
this.log('record TTL has been reached, searching routing for updates')
|
|
690
|
-
|
|
691
|
-
// add the local record to our list of resolved record, and also
|
|
692
|
-
// search the routing for updates - the most up to date record will be
|
|
693
|
-
// returned
|
|
694
|
-
records.push(record)
|
|
695
|
-
} catch (err) {
|
|
696
|
-
this.log('cached record was invalid', err)
|
|
697
|
-
await this.localStore.delete(routingKey, options)
|
|
698
|
-
}
|
|
699
|
-
} else {
|
|
700
|
-
log('ignoring local cache due to nocache=true option')
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
if (options.offline === true) {
|
|
705
|
-
throw new NotFoundError('Record was not present in the cache or has expired')
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
log('did not have record locally')
|
|
709
|
-
|
|
710
|
-
let foundInvalid = 0
|
|
711
|
-
|
|
712
|
-
await Promise.all(
|
|
713
|
-
this.routers.map(async (router) => {
|
|
714
|
-
let record: Uint8Array
|
|
715
|
-
|
|
716
|
-
try {
|
|
717
|
-
record = await router.get(routingKey, {
|
|
718
|
-
...options,
|
|
719
|
-
validate: false
|
|
720
|
-
})
|
|
721
|
-
} catch (err: any) {
|
|
722
|
-
log.error('error finding IPNS record', err)
|
|
723
|
-
|
|
724
|
-
return
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
try {
|
|
728
|
-
await ipnsValidator(routingKey, record)
|
|
729
|
-
|
|
730
|
-
records.push(record)
|
|
731
|
-
} catch (err) {
|
|
732
|
-
// we found a record, but the validator rejected it
|
|
733
|
-
foundInvalid++
|
|
734
|
-
log.error('error finding IPNS record', err)
|
|
735
|
-
}
|
|
736
|
-
})
|
|
737
|
-
)
|
|
738
|
-
|
|
739
|
-
if (records.length === 0) {
|
|
740
|
-
if (foundInvalid > 0) {
|
|
741
|
-
throw new RecordsFailedValidationError(`${foundInvalid > 1 ? `${foundInvalid} records` : 'Record'} found for routing key ${foundInvalid > 1 ? 'were' : 'was'} invalid`)
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
throw new NotFoundError('Could not find record for routing key')
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
const record = records[ipnsSelector(routingKey, records)]
|
|
748
|
-
|
|
749
|
-
await this.localStore.put(routingKey, record, options)
|
|
750
|
-
|
|
751
|
-
return unmarshalIPNSRecord(record)
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
async republishRecord (key: MultihashDigest<0x00 | 0x12> | string, record: IPNSRecord, options: RepublishRecordOptions = {}): Promise<void> {
|
|
755
|
-
let mh: MultihashDigest<0x00 | 0x12> | undefined
|
|
756
|
-
try {
|
|
757
|
-
mh = extractPublicKeyFromIPNSRecord(record)?.toMultihash() // embedded public key take precedence, if present
|
|
758
|
-
if (mh == null) {
|
|
759
|
-
// if no public key is embedded in the record, use the key that was passed in
|
|
760
|
-
if (typeof key === 'string') {
|
|
761
|
-
if (key.startsWith(IPNS_STRING_PREFIX)) {
|
|
762
|
-
// remove the /ipns/ prefix from the key
|
|
763
|
-
key = key.slice(IPNS_STRING_PREFIX.length)
|
|
764
|
-
}
|
|
765
|
-
// Convert string key to MultihashDigest
|
|
766
|
-
try {
|
|
767
|
-
mh = peerIdFromString(key).toMultihash()
|
|
768
|
-
} catch (err: any) {
|
|
769
|
-
throw new Error(`Invalid string key: ${err.message}`)
|
|
770
|
-
}
|
|
771
|
-
} else {
|
|
772
|
-
mh = key
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
if (mh == null) {
|
|
777
|
-
throw new Error('No public key multihash found to determine the routing key')
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
const routingKey = multihashToIPNSRoutingKey(mh)
|
|
781
|
-
const marshaledRecord = marshalIPNSRecord(record)
|
|
782
|
-
|
|
783
|
-
await ipnsValidator(routingKey, marshaledRecord) // validate that they key corresponds to the record
|
|
784
|
-
|
|
785
|
-
await this.localStore.put(routingKey, marshaledRecord, options) // add to local store
|
|
786
|
-
|
|
787
|
-
if (options.offline !== true) {
|
|
788
|
-
// publish record to routing
|
|
789
|
-
await Promise.all(this.routers.map(async r => { await r.put(routingKey, marshaledRecord, options) }))
|
|
790
|
-
}
|
|
791
|
-
} catch (err: any) {
|
|
792
|
-
options.onProgress?.(new CustomProgressEvent('ipns:republish:error', { key: mh, record, err }))
|
|
793
|
-
throw err
|
|
794
|
-
}
|
|
795
|
-
}
|
|
379
|
+
/**
|
|
380
|
+
* How many IPNS records to republish at once
|
|
381
|
+
*
|
|
382
|
+
* @default 5
|
|
383
|
+
*/
|
|
384
|
+
republishConcurrency?: number
|
|
796
385
|
}
|
|
797
386
|
|
|
798
|
-
export interface
|
|
387
|
+
export interface IPNSResolverOptions {
|
|
388
|
+
/**
|
|
389
|
+
* Different routing systems for IPNS publishing/resolving
|
|
390
|
+
*/
|
|
799
391
|
routers?: IPNSRouting[]
|
|
800
392
|
}
|
|
801
393
|
|
|
802
|
-
export function ipns (components: IPNSComponents,
|
|
803
|
-
return new
|
|
394
|
+
export function ipns (components: IPNSComponents, options: IPNSOptions = {}): IPNS {
|
|
395
|
+
return new IPNSClass(components, options)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export function ipnsResolver (components: IPNSResolverComponents, options: IPNSResolverOptions = {}): IPNSResolver {
|
|
399
|
+
const store = localStore(components.datastore, components.logger.forComponent('helia:ipns:local-store'))
|
|
400
|
+
const routers = [
|
|
401
|
+
localStoreRouting(store),
|
|
402
|
+
helia(components.routing),
|
|
403
|
+
...(options.routers ?? [])
|
|
404
|
+
]
|
|
405
|
+
|
|
406
|
+
return new IPNSResolverClass(components, {
|
|
407
|
+
routers,
|
|
408
|
+
localStore: store
|
|
409
|
+
})
|
|
804
410
|
}
|
|
805
411
|
|
|
806
|
-
export { ipnsValidator, type
|
|
412
|
+
export { ipnsValidator, type IPNSRoutingProgressEvents }
|
|
807
413
|
export { ipnsSelector } from 'ipns/selector'
|