Skip to content

Commit

Permalink
deps!: update ipns to v7.x.x (#106)
Browse files Browse the repository at this point in the history
Updates ipns to v7.x.x.

See the [release notes](https://github.com/ipfs/js-ipns/releases/tag/v7.0.0)
for full details.

BREAKING CHANGE: the `IPNSRecord` type returned from the `publish` method has changed
  • Loading branch information
achingbrain authored Sep 15, 2023
1 parent aaf402d commit 83a1d14
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 59 deletions.
2 changes: 1 addition & 1 deletion packages/interop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"go-ipfs": "^0.22.0",
"helia": "^2.0.1",
"ipfsd-ctl": "^13.0.0",
"ipns": "^6.0.0",
"ipns": "^7.0.1",
"it-all": "^3.0.2",
"it-last": "^3.0.1",
"it-map": "^3.0.3",
Expand Down
6 changes: 4 additions & 2 deletions packages/interop/test/fixtures/create-helia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { tcp } from '@libp2p/tcp'
import { MemoryBlockstore } from 'blockstore-core'
import { MemoryDatastore } from 'datastore-core'
import { createHelia } from 'helia'
import { createLibp2p, type Libp2p, type Libp2pOptions } from 'libp2p'
import { createLibp2p, type Libp2pOptions } from 'libp2p'
import type { Helia } from '@helia/interface'
import type { Libp2p } from '@libp2p/interface'
import type { IdentifyService } from 'libp2p/identify'

export async function createHeliaNode <T extends { identify: any }> (config: Libp2pOptions<T> = {}): Promise<Helia<Libp2p<T>>> {
export async function createHeliaNode <T extends { identify: IdentifyService }> (config: Libp2pOptions<T> = {}): Promise<Helia<Libp2p<T>>> {
const blockstore = new MemoryBlockstore()
const datastore = new MemoryDatastore()

Expand Down
2 changes: 1 addition & 1 deletion packages/interop/test/pubsub.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import { keyTypes } from './fixtures/key-types.js'
import { waitFor } from './fixtures/wait-for.js'
import type { Helia } from '@helia/interface'
import type { IPNS } from '@helia/ipns'
import type { Libp2p } from '@libp2p/interface'
import type { PubSub } from '@libp2p/interface/pubsub'
import type { Controller } from 'ipfsd-ctl'
import type { Libp2p } from 'libp2p'

const LIBP2P_KEY_CODEC = 0x72

Expand Down
2 changes: 1 addition & 1 deletion packages/ipns/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@
"@libp2p/record": "^3.0.0",
"hashlru": "^2.3.0",
"interface-datastore": "^8.0.0",
"ipns": "^6.0.0",
"ipns": "^7.0.1",
"is-ipfs": "^8.0.1",
"multiformats": "^12.0.1",
"p-queue": "^7.3.0",
Expand Down
62 changes: 18 additions & 44 deletions packages/ipns/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,11 @@
* @example
*
* ```typescript
* import { gossipsub } from '@chainsafe/libp2p-gossipsub'
* import { kadDHT } from '@libp2p/kad-dht'
* import { createLibp2p } from 'libp2p'
* import { createHelia } from 'helia'
* import { ipns, ipnsValidator, ipnsSelector } from '@helia/ipns'
* import { dht, pubsub } from '@helia/ipns/routing'
* import { unixfs } from '@helia/unixfs'
*
* const libp2p = await createLibp2p({
* dht: kadDHT({
* validators: {
* ipns: ipnsValidator
* },
* selectors: {
* ipns: ipnsSelector
* }
* }),
* pubsub: gossipsub()
* })
*
* const helia = await createHelia({
* libp2p,
* //.. other options
* })
* const helia = await createHelia()
* const name = ipns(helia, [
* dht(helia),
* pubsub(helia)
Expand Down Expand Up @@ -63,22 +44,20 @@
*/

import { CodeError } from '@libp2p/interface/errors'
import { isPeerId, type PeerId } from '@libp2p/interface/peer-id'
import { logger } from '@libp2p/logger'
import { peerIdFromString } from '@libp2p/peer-id'
import { create, marshal, peerIdToRoutingKey, unmarshal } from 'ipns'
import { ipnsSelector } from 'ipns/selector'
import { ipnsValidator } from 'ipns/validator'
import { CID } from 'multiformats/cid'
import { CustomProgressEvent } from 'progress-events'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import { localStore, type LocalStore } from './routing/local-store.js'
import { resolveDnslink } from './utils/resolve-dns-link.js'
import type { IPNSRouting, IPNSRoutingEvents } from './routing/index.js'
import type { AbortOptions } from '@libp2p/interface'
import type { PeerId } from '@libp2p/interface/peer-id'
import type { Datastore } from 'interface-datastore'
import type { IPNSEntry } from 'ipns'
import type { IPNSRecord } from 'ipns'
import type { ProgressEvent, ProgressOptions } from 'progress-events'

const log = logger('helia:ipns')
Expand All @@ -91,18 +70,18 @@ const DEFAULT_REPUBLISH_INTERVAL_MS = 23 * HOUR

export type PublishProgressEvents =
ProgressEvent<'ipns:publish:start'> |
ProgressEvent<'ipns:publish:success', IPNSEntry> |
ProgressEvent<'ipns:publish:success', IPNSRecord> |
ProgressEvent<'ipns:publish:error', Error>

export type ResolveProgressEvents =
ProgressEvent<'ipns:resolve:start', unknown> |
ProgressEvent<'ipns:resolve:success', IPNSEntry> |
ProgressEvent<'ipns:resolve:success', IPNSRecord> |
ProgressEvent<'ipns:resolve:error', Error>

export type RepublishProgressEvents =
ProgressEvent<'ipns:republish:start', unknown> |
ProgressEvent<'ipns:republish:success', IPNSEntry> |
ProgressEvent<'ipns:republish:error', { record: IPNSEntry, err: Error }>
ProgressEvent<'ipns:republish:success', IPNSRecord> |
ProgressEvent<'ipns:republish:error', { record: IPNSRecord, err: Error }>

export interface PublishOptions extends AbortOptions, ProgressOptions<PublishProgressEvents | IPNSRoutingEvents> {
/**
Expand All @@ -114,6 +93,12 @@ export interface PublishOptions extends AbortOptions, ProgressOptions<PublishPro
* Only publish to a local datastore (default: false)
*/
offline?: boolean

/**
* By default a IPNS V1 and a V2 signature is added to every record. Pass
* false here to only add a V2 signature. (default: true)
*/
v1Compatible?: boolean
}

export interface ResolveOptions extends AbortOptions, ProgressOptions<ResolveProgressEvents | IPNSRoutingEvents> {
Expand Down Expand Up @@ -143,7 +128,7 @@ export interface IPNS {
*
* If the valid is a PeerId, a recursive IPNS record will be created.
*/
publish: (key: PeerId, value: CID | PeerId, options?: PublishOptions) => Promise<IPNSEntry>
publish: (key: PeerId, value: CID | PeerId, options?: PublishOptions) => Promise<IPNSRecord>

/**
* Accepts a public key formatted as a libp2p PeerID and resolves the IPNS record
Expand Down Expand Up @@ -178,7 +163,7 @@ class DefaultIPNS implements IPNS {
this.localStore = localStore(components.datastore)
}

async publish (key: PeerId, value: CID | PeerId, options: PublishOptions = {}): Promise<IPNSEntry> {
async publish (key: PeerId, value: CID | PeerId, options: PublishOptions = {}): Promise<IPNSRecord> {
try {
let sequenceNumber = 1n
const routingKey = peerIdToRoutingKey(key)
Expand All @@ -190,18 +175,8 @@ class DefaultIPNS implements IPNS {
sequenceNumber = existingRecord.sequence + 1n
}

let str

if (isPeerId(value)) {
str = `/ipns/${value.toString()}`
} else {
str = `/ipfs/${value.toString()}`
}

const bytes = uint8ArrayFromString(str)

// create record
const record = await create(key, bytes, sequenceNumber, options.lifetime ?? DEFAULT_LIFETIME_MS)
const record = await create(key, value, sequenceNumber, options.lifetime ?? DEFAULT_LIFETIME_MS, options)
const marshaledRecord = marshal(record)

await this.localStore.put(routingKey, marshaledRecord, options)
Expand All @@ -221,9 +196,8 @@ class DefaultIPNS implements IPNS {
async resolve (key: PeerId, options: ResolveOptions = {}): Promise<CID> {
const routingKey = peerIdToRoutingKey(key)
const record = await this.#findIpnsRecord(routingKey, options)
const str = uint8ArrayToString(record.value)

return this.#resolve(str, options)
return this.#resolve(record.value, options)
}

async resolveDns (domain: string, options: ResolveDNSOptions = {}): Promise<CID> {
Expand Down Expand Up @@ -285,7 +259,7 @@ class DefaultIPNS implements IPNS {
throw new Error('Invalid value')
}

async #findIpnsRecord (routingKey: Uint8Array, options: ResolveOptions = {}): Promise<IPNSEntry> {
async #findIpnsRecord (routingKey: Uint8Array, options: ResolveOptions = {}): Promise<IPNSRecord> {
let routers = [
this.localStore,
...this.routers
Expand Down
18 changes: 8 additions & 10 deletions packages/ipns/test/resolve.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { create, marshal, peerIdToRoutingKey } from 'ipns'
import { CID } from 'multiformats/cid'
import Sinon from 'sinon'
import { type StubbedInstance, stubInterface } from 'sinon-ts'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import { ipns } from '../src/index.js'
import type { IPNS, IPNSRouting } from '../src/index.js'
Expand Down Expand Up @@ -39,7 +38,7 @@ describe('resolve', () => {
throw new Error('Did not resolve entry')
}

expect(resolvedValue.toString()).to.equal(cid.toString())
expect(resolvedValue.toString()).to.equal(cid.toV1().toString())
})

it('should resolve a record offline', async () => {
Expand All @@ -58,7 +57,7 @@ describe('resolve', () => {
throw new Error('Did not resolve entry')
}

expect(resolvedValue.toString()).to.equal(cid.toString())
expect(resolvedValue.toString()).to.equal(cid.toV1().toString())
})

it('should resolve a recursive record', async () => {
Expand All @@ -73,7 +72,7 @@ describe('resolve', () => {
throw new Error('Did not resolve entry')
}

expect(resolvedValue.toString()).to.equal(cid.toString())
expect(resolvedValue.toString()).to.equal(cid.toV1().toString())
})

it('should resolve /ipns/tableflip.io', async function () {
Expand Down Expand Up @@ -112,14 +111,13 @@ describe('resolve', () => {

expect(datastore.has(dhtKey)).to.be.false('already had record')

const bytes = uint8ArrayFromString(`/ipfs/${cid.toString()}`)
const record = await create(peerId, bytes, 0n, 60000)
const record = await create(peerId, cid, 0n, 60000)
const marshalledRecord = marshal(record)

routing.get.withArgs(routingKey).resolves(marshalledRecord)

const result = await name.resolve(peerId)
expect(result.toString()).to.equal(cid.toString(), 'incorrect record resolved')
expect(result.toString()).to.equal(cid.toV1().toString(), 'incorrect record resolved')

expect(datastore.has(dhtKey)).to.be.true('did not cache record locally')
})
Expand All @@ -129,8 +127,8 @@ describe('resolve', () => {
const routingKey = peerIdToRoutingKey(peerId)
const dhtKey = new Key('/dht/record/' + uint8ArrayToString(routingKey, 'base32'), false)

const marshalledRecordA = marshal(await create(peerId, uint8ArrayFromString(`/ipfs/${cid.toString()}`), 0n, 60000))
const marshalledRecordB = marshal(await create(peerId, uint8ArrayFromString(`/ipfs/${cid.toString()}`), 10n, 60000))
const marshalledRecordA = marshal(await create(peerId, cid, 0n, 60000))
const marshalledRecordB = marshal(await create(peerId, cid, 10n, 60000))

// records should not match
expect(marshalledRecordA).to.not.equalBytes(marshalledRecordB)
Expand All @@ -140,7 +138,7 @@ describe('resolve', () => {
routing.get.withArgs(routingKey).resolves(marshalledRecordB)

const result = await name.resolve(peerId)
expect(result.toString()).to.equal(cid.toString(), 'incorrect record resolved')
expect(result.toString()).to.equal(cid.toV1().toString(), 'incorrect record resolved')

const cached = await datastore.get(dhtKey)
const record = Libp2pRecord.deserialize(cached)
Expand Down

0 comments on commit 83a1d14

Please sign in to comment.