@helia/ipns 9.2.1-eb1908b3 → 9.2.1-ed6c3b79
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 +21 -57
- package/dist/index.min.js +5 -16
- package/dist/index.min.js.map +4 -4
- package/dist/src/errors.d.ts +33 -5
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +33 -20
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +62 -99
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +21 -60
- package/dist/src/index.js.map +1 -1
- package/dist/src/ipns/publisher.d.ts +5 -9
- package/dist/src/ipns/publisher.d.ts.map +1 -1
- package/dist/src/ipns/publisher.js +30 -22
- package/dist/src/ipns/publisher.js.map +1 -1
- package/dist/src/ipns/republisher.d.ts +3 -5
- package/dist/src/ipns/republisher.d.ts.map +1 -1
- package/dist/src/ipns/republisher.js +18 -9
- package/dist/src/ipns/republisher.js.map +1 -1
- package/dist/src/ipns/resolver.d.ts +6 -5
- package/dist/src/ipns/resolver.d.ts.map +1 -1
- package/dist/src/ipns/resolver.js +32 -78
- package/dist/src/ipns/resolver.js.map +1 -1
- package/dist/src/ipns.d.ts +6 -4
- package/dist/src/ipns.d.ts.map +1 -1
- package/dist/src/ipns.js +33 -4
- package/dist/src/ipns.js.map +1 -1
- package/dist/src/pb/ipns.d.ts +62 -0
- package/dist/src/pb/ipns.d.ts.map +1 -0
- package/dist/src/pb/ipns.js +203 -0
- package/dist/src/pb/ipns.js.map +1 -0
- package/dist/src/pb/metadata.d.ts +1 -1
- package/dist/src/pb/metadata.d.ts.map +1 -1
- package/dist/src/records.d.ts +155 -0
- package/dist/src/records.d.ts.map +1 -0
- package/dist/src/records.js +88 -0
- package/dist/src/records.js.map +1 -0
- package/dist/src/routing/pubsub.d.ts +3 -0
- package/dist/src/routing/pubsub.d.ts.map +1 -1
- package/dist/src/routing/pubsub.js +15 -10
- package/dist/src/routing/pubsub.js.map +1 -1
- package/dist/src/selector.d.ts +14 -0
- package/dist/src/selector.d.ts.map +1 -0
- package/dist/src/selector.js +47 -0
- package/dist/src/selector.js.map +1 -0
- package/dist/src/utils.d.ts +29 -2
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +308 -0
- package/dist/src/utils.js.map +1 -1
- package/dist/src/validator.d.ts +18 -0
- package/dist/src/validator.d.ts.map +1 -0
- package/dist/src/validator.js +58 -0
- package/dist/src/validator.js.map +1 -0
- package/package.json +24 -23
- package/src/errors.ts +40 -25
- package/src/index.ts +63 -100
- package/src/ipns/publisher.ts +34 -29
- package/src/ipns/republisher.ts +24 -13
- package/src/ipns/resolver.ts +40 -88
- package/src/ipns.ts +44 -7
- package/src/pb/ipns.proto +39 -0
- package/src/pb/ipns.ts +280 -0
- package/src/pb/metadata.ts +1 -1
- package/src/records.ts +273 -0
- package/src/routing/pubsub.ts +17 -10
- package/src/selector.ts +55 -0
- package/src/utils.ts +371 -2
- package/src/validator.ts +67 -0
package/src/ipns/republisher.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { Queue, repeatingTask } from '@libp2p/utils'
|
|
2
|
-
import { createIPNSRecord, marshalIPNSRecord, unmarshalIPNSRecord } from 'ipns'
|
|
3
2
|
import { DEFAULT_REPUBLISH_CONCURRENCY, DEFAULT_REPUBLISH_INTERVAL_MS, DEFAULT_TTL_NS } from '../constants.ts'
|
|
3
|
+
import { createIPNSRecord } from '../records.ts'
|
|
4
|
+
import { marshalIPNSRecord, unmarshalIPNSRecord } from '../utils.ts'
|
|
4
5
|
import { shouldRepublish } from '../utils.ts'
|
|
6
|
+
import type { IPNSRecord } from '../index.ts'
|
|
5
7
|
import type { LocalStore } from '../local-store.ts'
|
|
6
8
|
import type { IPNSRouting } from '../routing/index.ts'
|
|
7
|
-
import type {
|
|
8
|
-
import type {
|
|
9
|
+
import type { Keychain, PrivateKey } from '@helia/interface'
|
|
10
|
+
import type { AbortOptions, ComponentLogger, Logger } from '@libp2p/interface'
|
|
9
11
|
import type { RepeatingTask } from '@libp2p/utils'
|
|
10
|
-
import type { IPNSRecord } from 'ipns'
|
|
11
12
|
|
|
12
13
|
export interface IPNSRepublisherComponents {
|
|
13
14
|
logger: ComponentLogger
|
|
14
|
-
|
|
15
|
+
keychain: Keychain
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export interface IPNSRepublisherInit {
|
|
@@ -33,9 +34,9 @@ export class IPNSRepublisher {
|
|
|
33
34
|
constructor (components: IPNSRepublisherComponents, init: IPNSRepublisherInit) {
|
|
34
35
|
this.log = components.logger.forComponent('helia:ipns')
|
|
35
36
|
this.localStore = init.localStore
|
|
36
|
-
this.keychain = components.
|
|
37
|
+
this.keychain = components.keychain
|
|
37
38
|
this.republishConcurrency = init.republishConcurrency || DEFAULT_REPUBLISH_CONCURRENCY
|
|
38
|
-
this.started =
|
|
39
|
+
this.started = false
|
|
39
40
|
this.routers = init.routers ?? []
|
|
40
41
|
|
|
41
42
|
this.republishTask = repeatingTask(this.#republish.bind(this), init.republishInterval ?? DEFAULT_REPUBLISH_INTERVAL_MS, {
|
|
@@ -78,18 +79,21 @@ export class IPNSRepublisher {
|
|
|
78
79
|
|
|
79
80
|
try {
|
|
80
81
|
const recordsToRepublish: Array<{ routingKey: Uint8Array, record: IPNSRecord }> = []
|
|
82
|
+
let listed = 0
|
|
81
83
|
|
|
82
84
|
// Find all records using the localStore.list method
|
|
83
85
|
for await (const { routingKey, record, metadata, created } of this.localStore.list(options)) {
|
|
86
|
+
listed++
|
|
87
|
+
|
|
84
88
|
if (metadata == null) {
|
|
85
89
|
// Skip if no metadata is found from before we started
|
|
86
90
|
// storing metadata or for records republished without a key
|
|
87
|
-
this.log(
|
|
91
|
+
this.log('no metadata found for record %b, skipping', routingKey)
|
|
88
92
|
continue
|
|
89
93
|
}
|
|
90
94
|
let ipnsRecord: IPNSRecord
|
|
91
95
|
try {
|
|
92
|
-
ipnsRecord = unmarshalIPNSRecord(record)
|
|
96
|
+
ipnsRecord = await unmarshalIPNSRecord(routingKey, record, this.keychain, options)
|
|
93
97
|
} catch (err: any) {
|
|
94
98
|
this.log.error('error unmarshaling record - %e', err)
|
|
95
99
|
continue
|
|
@@ -97,7 +101,7 @@ export class IPNSRepublisher {
|
|
|
97
101
|
|
|
98
102
|
// Only republish records that are within the DHT or record expiry threshold
|
|
99
103
|
if (!shouldRepublish(ipnsRecord, created)) {
|
|
100
|
-
this.log.trace(
|
|
104
|
+
this.log.trace('skipping record %b within republish threshold', routingKey)
|
|
101
105
|
continue
|
|
102
106
|
}
|
|
103
107
|
const sequenceNumber = ipnsRecord.sequence + 1n
|
|
@@ -110,16 +114,23 @@ export class IPNSRepublisher {
|
|
|
110
114
|
this.log.error('missing key %s, skipping republishing record - %e', metadata.keyName, err)
|
|
111
115
|
continue
|
|
112
116
|
}
|
|
117
|
+
|
|
113
118
|
try {
|
|
114
|
-
const updatedRecord = await createIPNSRecord(privKey, ipnsRecord.value, sequenceNumber, metadata.lifetime, {
|
|
115
|
-
|
|
119
|
+
const updatedRecord = await createIPNSRecord(privKey, ipnsRecord.value, sequenceNumber, metadata.lifetime, {
|
|
120
|
+
...options,
|
|
121
|
+
ttlNs
|
|
122
|
+
})
|
|
123
|
+
recordsToRepublish.push({
|
|
124
|
+
routingKey,
|
|
125
|
+
record: updatedRecord
|
|
126
|
+
})
|
|
116
127
|
} catch (err: any) {
|
|
117
128
|
this.log.error('error creating updated IPNS record for %s - %e', routingKey, err)
|
|
118
129
|
continue
|
|
119
130
|
}
|
|
120
131
|
}
|
|
121
132
|
|
|
122
|
-
this.log(`found ${recordsToRepublish.length} records to republish`)
|
|
133
|
+
this.log(`found ${recordsToRepublish.length}/${listed} records to republish`)
|
|
123
134
|
|
|
124
135
|
// Republish each record
|
|
125
136
|
for (const { routingKey, record } of recordsToRepublish) {
|
package/src/ipns/resolver.ts
CHANGED
|
@@ -1,33 +1,21 @@
|
|
|
1
|
-
import { isPeerId, isPublicKey } from '@libp2p/interface'
|
|
2
|
-
import { multihashToIPNSRoutingKey, unmarshalIPNSRecord } from 'ipns'
|
|
3
|
-
import { ipnsSelector } from 'ipns/selector'
|
|
4
|
-
import { ipnsValidator } from 'ipns/validator'
|
|
5
|
-
import { base36 } from 'multiformats/bases/base36'
|
|
6
|
-
import { base58btc } from 'multiformats/bases/base58'
|
|
7
|
-
import { CID } from 'multiformats/cid'
|
|
8
|
-
import * as Digest from 'multiformats/hashes/digest'
|
|
9
1
|
import { DEFAULT_TTL_NS } from '../constants.ts'
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
2
|
+
import { RecordNotFoundError, RecordsFailedValidationError } from '../errors.ts'
|
|
3
|
+
import { ipnsSelector } from '../selector.ts'
|
|
4
|
+
import { multihashToIPNSRoutingKey, unmarshalIPNSRecord, normalizeKey, IPNS_STRING_PREFIX } from '../utils.ts'
|
|
5
|
+
import { ipnsValidator } from '../validator.ts'
|
|
6
|
+
import type { IPNSRecord, ResolveOptions, ResolveResult } from '../index.ts'
|
|
13
7
|
import type { LocalStore } from '../local-store.ts'
|
|
14
8
|
import type { IPNSRouting } from '../routing/index.ts'
|
|
15
|
-
import type { Routing } from '@helia/interface'
|
|
16
|
-
import type { ComponentLogger, Logger
|
|
9
|
+
import type { Routing, Keychain } from '@helia/interface'
|
|
10
|
+
import type { ComponentLogger, Logger } from '@libp2p/interface'
|
|
17
11
|
import type { Datastore } from 'interface-datastore'
|
|
18
|
-
import type { IPNSRecord } from 'ipns'
|
|
19
|
-
import type { MultibaseDecoder } from 'multiformats/bases/interface'
|
|
20
12
|
import type { MultihashDigest } from 'multiformats/hashes/interface'
|
|
21
13
|
|
|
22
|
-
const bases: Record<string, MultibaseDecoder<string>> = {
|
|
23
|
-
[base36.prefix]: base36,
|
|
24
|
-
[base58btc.prefix]: base58btc
|
|
25
|
-
}
|
|
26
|
-
|
|
27
14
|
export interface IPNSResolverComponents {
|
|
28
15
|
datastore: Datastore
|
|
29
16
|
routing: Routing
|
|
30
17
|
logger: ComponentLogger
|
|
18
|
+
keychain: Keychain
|
|
31
19
|
}
|
|
32
20
|
|
|
33
21
|
export interface IPNResolverInit {
|
|
@@ -39,80 +27,37 @@ export class IPNSResolver {
|
|
|
39
27
|
public readonly routers: IPNSRouting[]
|
|
40
28
|
private readonly localStore: LocalStore
|
|
41
29
|
private readonly log: Logger
|
|
30
|
+
private keychain: Keychain
|
|
42
31
|
|
|
43
32
|
constructor (components: IPNSResolverComponents, init: IPNResolverInit) {
|
|
44
33
|
this.log = components.logger.forComponent('helia:ipns')
|
|
45
34
|
this.localStore = init.localStore
|
|
46
35
|
this.routers = init.routers
|
|
36
|
+
this.keychain = components.keychain
|
|
47
37
|
}
|
|
48
38
|
|
|
49
|
-
async resolve (key:
|
|
50
|
-
|
|
51
|
-
const routingKey = multihashToIPNSRoutingKey(digest)
|
|
52
|
-
const record = await this.#findIpnsRecord(routingKey, options)
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
...(await this.#resolve(record.value, options)),
|
|
56
|
-
record
|
|
57
|
-
}
|
|
58
|
-
}
|
|
39
|
+
async * resolve (key: MultihashDigest, options: ResolveOptions = {}): AsyncGenerator<ResolveResult> {
|
|
40
|
+
let { digest } = normalizeKey(key)
|
|
59
41
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const scheme = parts[1]
|
|
64
|
-
|
|
65
|
-
if (scheme === 'ipns') {
|
|
66
|
-
const str = parts[2]
|
|
67
|
-
const prefix = str.substring(0, 1)
|
|
68
|
-
let buf: Uint8Array | undefined
|
|
69
|
-
|
|
70
|
-
if (prefix === '1' || prefix === 'Q') {
|
|
71
|
-
buf = base58btc.decode(`z${str}`)
|
|
72
|
-
} else if (bases[prefix] != null) {
|
|
73
|
-
buf = bases[prefix].decode(str)
|
|
74
|
-
} else {
|
|
75
|
-
throw new UnsupportedMultibasePrefixError(`Unsupported multibase prefix "${prefix}"`)
|
|
76
|
-
}
|
|
42
|
+
while (true) {
|
|
43
|
+
const routingKey = multihashToIPNSRoutingKey(digest)
|
|
44
|
+
const record = await this.#findIpnsRecord(routingKey, options)
|
|
77
45
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
digest = Digest.decode(buf)
|
|
82
|
-
} catch {
|
|
83
|
-
digest = CID.decode(buf).multihash
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (!isCodec(digest, IDENTITY_CODEC) && !isCodec(digest, SHA2_256_CODEC)) {
|
|
87
|
-
throw new UnsupportedMultihashCodecError(`Unsupported multihash codec "${digest.code}"`)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const { cid } = await this.resolve(digest, options)
|
|
91
|
-
const path = parts.slice(3).join('/')
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
cid,
|
|
95
|
-
path: path === '' ? undefined : path
|
|
96
|
-
}
|
|
97
|
-
} else if (scheme === 'ipfs') {
|
|
98
|
-
const cid = CID.parse(parts[2])
|
|
99
|
-
const path = parts.slice(3).join('/')
|
|
46
|
+
yield {
|
|
47
|
+
record
|
|
48
|
+
}
|
|
100
49
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
50
|
+
if (!record.value.startsWith(IPNS_STRING_PREFIX)) {
|
|
51
|
+
// not a recursive record
|
|
52
|
+
break
|
|
105
53
|
}
|
|
106
|
-
} catch (err) {
|
|
107
|
-
this.log.error('error parsing ipfs path - %e', err)
|
|
108
|
-
}
|
|
109
54
|
|
|
110
|
-
|
|
111
|
-
|
|
55
|
+
({ digest } = normalizeKey(record.value))
|
|
56
|
+
}
|
|
112
57
|
}
|
|
113
58
|
|
|
114
59
|
async #findIpnsRecord (routingKey: Uint8Array, options: ResolveOptions = {}): Promise<IPNSRecord> {
|
|
115
|
-
const records:
|
|
60
|
+
const records: IPNSRecord[] = []
|
|
116
61
|
const cached = await this.localStore.has(routingKey, options)
|
|
117
62
|
|
|
118
63
|
if (cached) {
|
|
@@ -121,17 +66,19 @@ export class IPNSResolver {
|
|
|
121
66
|
if (options.nocache !== true) {
|
|
122
67
|
try {
|
|
123
68
|
// check the local cache first
|
|
124
|
-
const { record, created } = await this.localStore.get(routingKey, options)
|
|
69
|
+
const { record: marshaledIPNSRecord, created } = await this.localStore.get(routingKey, options)
|
|
125
70
|
|
|
126
71
|
this.log('record retrieved from cache')
|
|
127
72
|
|
|
73
|
+
// unmarshal the record
|
|
74
|
+
const ipnsRecord = await unmarshalIPNSRecord(routingKey, marshaledIPNSRecord, this.keychain, options)
|
|
75
|
+
|
|
128
76
|
// validate the record
|
|
129
|
-
await ipnsValidator(
|
|
77
|
+
await ipnsValidator(ipnsRecord, options)
|
|
130
78
|
|
|
131
79
|
this.log('record was valid')
|
|
132
80
|
|
|
133
81
|
// check the TTL
|
|
134
|
-
const ipnsRecord = unmarshalIPNSRecord(record)
|
|
135
82
|
|
|
136
83
|
// IPNS TTL is in nanoseconds, convert to milliseconds, default to one
|
|
137
84
|
// hour
|
|
@@ -155,7 +102,7 @@ export class IPNSResolver {
|
|
|
155
102
|
// add the local record to our list of resolved record, and also
|
|
156
103
|
// search the routing for updates - the most up to date record will be
|
|
157
104
|
// returned
|
|
158
|
-
records.push(
|
|
105
|
+
records.push(ipnsRecord)
|
|
159
106
|
} catch (err) {
|
|
160
107
|
this.log('cached record was invalid - %e', err)
|
|
161
108
|
await this.localStore.delete(routingKey, options)
|
|
@@ -176,10 +123,10 @@ export class IPNSResolver {
|
|
|
176
123
|
|
|
177
124
|
await Promise.all(
|
|
178
125
|
this.routers.map(async (router) => {
|
|
179
|
-
let
|
|
126
|
+
let marshaledIPNSRecord: Uint8Array
|
|
180
127
|
|
|
181
128
|
try {
|
|
182
|
-
|
|
129
|
+
marshaledIPNSRecord = await router.get(routingKey, {
|
|
183
130
|
...options,
|
|
184
131
|
validate: false
|
|
185
132
|
})
|
|
@@ -191,7 +138,12 @@ export class IPNSResolver {
|
|
|
191
138
|
}
|
|
192
139
|
|
|
193
140
|
try {
|
|
194
|
-
|
|
141
|
+
// unmarshal ensures that (1) SignatureV2 and Data are present, (2) that ValidityType
|
|
142
|
+
// and Validity are of valid types and have a value, (3) that CBOR data matches protobuf
|
|
143
|
+
// if it's a V1+V2 record
|
|
144
|
+
const record = await unmarshalIPNSRecord(routingKey, marshaledIPNSRecord, this.keychain, options)
|
|
145
|
+
|
|
146
|
+
await ipnsValidator(record, options)
|
|
195
147
|
|
|
196
148
|
records.push(record)
|
|
197
149
|
} catch (err) {
|
|
@@ -212,8 +164,8 @@ export class IPNSResolver {
|
|
|
212
164
|
|
|
213
165
|
const record = records[ipnsSelector(routingKey, records)]
|
|
214
166
|
|
|
215
|
-
await this.localStore.put(routingKey, record, options)
|
|
167
|
+
await this.localStore.put(routingKey, record.bytes, options)
|
|
216
168
|
|
|
217
|
-
return
|
|
169
|
+
return record
|
|
218
170
|
}
|
|
219
171
|
}
|
package/src/ipns.ts
CHANGED
|
@@ -5,10 +5,15 @@ import { IPNSResolver } from './ipns/resolver.ts'
|
|
|
5
5
|
import { localStore } from './local-store.ts'
|
|
6
6
|
import { helia } from './routing/helia.ts'
|
|
7
7
|
import { localStoreRouting } from './routing/local-store.ts'
|
|
8
|
-
import
|
|
8
|
+
import { ipnsSelector } from './selector.ts'
|
|
9
|
+
import { normalizeKey, normalizeValue, unmarshalIPNSRecord } from './utils.ts'
|
|
10
|
+
import { ipnsValidator } from './validator.ts'
|
|
11
|
+
import type { IPNSComponents, IPNS as IPNSInterface, IPNSOptions, PublishResult, PublishOptions, ResolveOptions, ResolveResult } from './index.ts'
|
|
9
12
|
import type { LocalStore } from './local-store.ts'
|
|
10
13
|
import type { IPNSRouting } from './routing/index.ts'
|
|
11
|
-
import type {
|
|
14
|
+
import type { PublicKey } from '@helia/interface'
|
|
15
|
+
import type { AbortOptions, Libp2p, Startable } from '@libp2p/interface'
|
|
16
|
+
import type { ValidateFn, SelectFn } from '@libp2p/kad-dht'
|
|
12
17
|
import type { MultihashDigest } from 'multiformats/hashes/interface'
|
|
13
18
|
|
|
14
19
|
export class IPNS implements IPNSInterface, Startable {
|
|
@@ -17,11 +22,13 @@ export class IPNS implements IPNSInterface, Startable {
|
|
|
17
22
|
private readonly republisher: IPNSRepublisher
|
|
18
23
|
private readonly resolver: IPNSResolver
|
|
19
24
|
private readonly localStore: LocalStore
|
|
25
|
+
private readonly components: IPNSComponents
|
|
20
26
|
private started: boolean
|
|
21
27
|
|
|
22
28
|
constructor (components: IPNSComponents, init: IPNSOptions = {}) {
|
|
23
29
|
this.localStore = localStore(components.datastore, components.logger.forComponent('helia:ipns:local-store'))
|
|
24
|
-
this.
|
|
30
|
+
this.components = components
|
|
31
|
+
this.started = false
|
|
25
32
|
|
|
26
33
|
this.routers = [
|
|
27
34
|
localStoreRouting(this.localStore),
|
|
@@ -53,6 +60,26 @@ export class IPNS implements IPNSInterface, Startable {
|
|
|
53
60
|
if (this.started) {
|
|
54
61
|
this.republisher.start()
|
|
55
62
|
}
|
|
63
|
+
|
|
64
|
+
for (const component of Object.values(this.components)) {
|
|
65
|
+
if (isLibp2p(component)) {
|
|
66
|
+
for (const service of Object.values(component.services)) {
|
|
67
|
+
if (isKadDHT(service)) {
|
|
68
|
+
// @ ts-expect-error https://github.com/libp2p/js-libp2p/pull/3506
|
|
69
|
+
service.selectors.ipns = async (key: Uint8Array, values: Uint8Array[]): Promise<number> => {
|
|
70
|
+
const records = await Promise.all(values.map(buf => unmarshalIPNSRecord(key, buf, this.components.keychain)))
|
|
71
|
+
|
|
72
|
+
return ipnsSelector(key, records)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
service.validators.ipns = async (key: Uint8Array, value: Uint8Array): Promise<void> => {
|
|
76
|
+
const record = await unmarshalIPNSRecord(key, value, this.components.keychain)
|
|
77
|
+
await ipnsValidator(record)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
56
83
|
}
|
|
57
84
|
|
|
58
85
|
start (): void {
|
|
@@ -73,15 +100,25 @@ export class IPNS implements IPNSInterface, Startable {
|
|
|
73
100
|
this.republisher.stop()
|
|
74
101
|
}
|
|
75
102
|
|
|
76
|
-
async publish (keyName: string, value:
|
|
77
|
-
return this.publisher.publish(keyName, value, options)
|
|
103
|
+
async publish (keyName: string, value: PublicKey | CID | MultihashDigest | string, options: PublishOptions = {}): Promise<PublishResult> {
|
|
104
|
+
return this.publisher.publish(keyName, normalizeValue(value), options)
|
|
78
105
|
}
|
|
79
106
|
|
|
80
|
-
async resolve (key: CID<unknown, 0x72
|
|
81
|
-
|
|
107
|
+
async * resolve (key: PublicKey | CID<unknown, 0x72> | MultihashDigest | string, options: ResolveOptions = {}): AsyncGenerator<ResolveResult> {
|
|
108
|
+
const { digest } = normalizeKey(key)
|
|
109
|
+
|
|
110
|
+
yield * this.resolver.resolve(digest, options)
|
|
82
111
|
}
|
|
83
112
|
|
|
84
113
|
async unpublish (keyName: string, options?: AbortOptions): Promise<void> {
|
|
85
114
|
return this.publisher.unpublish(keyName, options)
|
|
86
115
|
}
|
|
87
116
|
}
|
|
117
|
+
|
|
118
|
+
function isLibp2p (obj?: any): obj is Libp2p {
|
|
119
|
+
return obj?.services != null
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function isKadDHT (obj?: any): obj is { validators: Record<string, ValidateFn>, selectors: Record<string, SelectFn> } {
|
|
123
|
+
return obj?.validators != null && obj?.selectors != null
|
|
124
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// https://github.com/ipfs/boxo/blob/main/ipns/pb/record.proto
|
|
2
|
+
|
|
3
|
+
syntax = "proto3";
|
|
4
|
+
|
|
5
|
+
message IpnsEntry {
|
|
6
|
+
enum ValidityType {
|
|
7
|
+
// setting an EOL says "this record is valid until..."
|
|
8
|
+
EOL = 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// legacy V1 copy of data[Value]
|
|
12
|
+
optional bytes value = 1;
|
|
13
|
+
|
|
14
|
+
// legacy V1 field, verify 'signatureV2' instead
|
|
15
|
+
optional bytes signatureV1 = 2;
|
|
16
|
+
|
|
17
|
+
// legacy V1 copies of data[ValidityType] and data[Validity]
|
|
18
|
+
optional ValidityType validityType = 3;
|
|
19
|
+
optional bytes validity = 4;
|
|
20
|
+
|
|
21
|
+
// legacy V1 copy of data[Sequence]
|
|
22
|
+
optional uint64 sequence = 5;
|
|
23
|
+
|
|
24
|
+
// legacy V1 copy copy of data[TTL]
|
|
25
|
+
optional uint64 ttl = 6;
|
|
26
|
+
|
|
27
|
+
// Optional Public Key to be used for signature verification.
|
|
28
|
+
// Used for big keys such as old RSA keys. Including the public key as part of
|
|
29
|
+
// the record itself makes it verifiable in offline mode, without any additional lookup.
|
|
30
|
+
// For newer Ed25519 keys, the public key is small enough that it can be embedded in the
|
|
31
|
+
// IPNS Name itself, making this field unnecessary.
|
|
32
|
+
optional bytes publicKey = 7;
|
|
33
|
+
|
|
34
|
+
// (mandatory V2) signature of the IPNS record
|
|
35
|
+
optional bytes signatureV2 = 8;
|
|
36
|
+
|
|
37
|
+
// (mandatory V2) extensible record data in DAG-CBOR format
|
|
38
|
+
optional bytes data = 9;
|
|
39
|
+
}
|