diff --git a/src/index.ts b/src/index.ts index baae18f..aac9f0c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,6 +16,7 @@ import type { CID } from 'multiformats/cid' const log = logger('ipns') const ID_MULTIHASH_CODE = identity.code +const DEFAULT_TTL_NS = 60 * 60 * 1e+9 // 1 Hour or 3600 Seconds export const namespace = '/ipns/' export const namespaceLength = namespace.length @@ -128,6 +129,7 @@ export interface IDKeys { } export interface CreateOptions { + ttlNs?: number | bigint v1Compatible?: boolean } @@ -140,7 +142,8 @@ export interface CreateV2Options { } const defaultCreateOptions: CreateOptions = { - v1Compatible: true + v1Compatible: true, + ttlNs: DEFAULT_TTL_NS } /** @@ -167,10 +170,9 @@ export async function create (peerId: PeerId, value: CID | PeerId | string, seq: // Validity in ISOString with nanoseconds precision and validity type EOL const expirationDate = new NanoDate(Date.now() + Number(lifetime)) const validityType = IpnsEntry.ValidityType.EOL - const [ms, ns] = lifetime.toString().split('.') - const lifetimeNs = (BigInt(ms) * BigInt(100000)) + BigInt(ns ?? '0') + const ttlNs = BigInt(options.ttlNs != null ? options.ttlNs : DEFAULT_TTL_NS) - return _create(peerId, value, seq, validityType, expirationDate.toString(), lifetimeNs, options) + return _create(peerId, value, seq, validityType, expirationDate.toString(), ttlNs, options) } /** @@ -195,9 +197,7 @@ export async function createWithExpiration (peerId: PeerId, value: CID | PeerId export async function createWithExpiration (peerId: PeerId, value: CID | PeerId | string, seq: number | bigint, expiration: string, options: CreateOptions = defaultCreateOptions): Promise { const expirationDate = NanoDate.fromString(expiration) const validityType = IpnsEntry.ValidityType.EOL - - const ttlMs = expirationDate.toDate().getTime() - Date.now() - const ttlNs = (BigInt(ttlMs) * BigInt(100000)) + BigInt(expirationDate.getNano()) + const ttlNs = BigInt(options.ttlNs != null ? options.ttlNs : DEFAULT_TTL_NS) return _create(peerId, value, seq, validityType, expirationDate.toString(), ttlNs, options) } diff --git a/test/index.spec.ts b/test/index.spec.ts index 307c0b2..1800945 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -32,6 +32,7 @@ describe('ipns', function () { it('should create an ipns record (V1+V2) correctly', async () => { const sequence = 0 + const ttl = BigInt(60 * 60 * 1e+9) const validity = 1000000 const record = await ipns.create(peerId, contentPath, sequence, validity) @@ -40,7 +41,7 @@ describe('ipns', function () { expect(record.validityType).to.equal(IpnsEntry.ValidityType.EOL) expect(record.validity).to.exist() expect(record.sequence).to.equal(BigInt(0)) - expect(record.ttl).to.equal(BigInt(validity * 100000)) + expect(record.ttl).to.equal(ttl) expect(record.signatureV1).to.exist() expect(record.signatureV2).to.exist() expect(record.data).to.exist() @@ -51,7 +52,7 @@ describe('ipns', function () { expect(pb.validityType).to.equal(IpnsEntry.ValidityType.EOL) expect(pb.validity).to.exist() expect(pb.sequence).to.equal(BigInt(sequence)) - expect(pb.ttl).to.equal(BigInt(validity * 100000)) + expect(pb.ttl).to.equal(ttl) expect(pb.signatureV1).to.exist() expect(pb.signatureV2).to.exist() expect(pb.data).to.exist() @@ -67,6 +68,7 @@ describe('ipns', function () { it('should create an ipns record (V2) correctly', async () => { const sequence = 0 + const ttl = BigInt(60 * 60 * 1e+9) const validity = 1000000 const record = await ipns.create(peerId, contentPath, sequence, validity, { v1Compatible: false }) @@ -75,7 +77,7 @@ describe('ipns', function () { expect(record.validityType).to.equal(IpnsEntry.ValidityType.EOL) expect(record.validity).to.exist() expect(record.sequence).to.equal(BigInt(0)) - expect(record.ttl).to.equal(BigInt(validity * 100000)) + expect(record.ttl).to.equal(ttl) expect(record.signatureV2).to.exist() expect(record).to.not.have.property('signatureV1') expect(record.data).to.exist() @@ -97,7 +99,7 @@ describe('ipns', function () { expect(data.ValidityType).to.equal(IpnsEntry.ValidityType.EOL) expect(data.Validity).to.exist() expect(data.Sequence).to.equal(BigInt(sequence)) - expect(data.TTL).to.equal(BigInt(validity * 100000)) + expect(data.TTL).to.equal(ttl) }) it('should be able to create a record (V1+V2) with a fixed expiration', async () => { @@ -130,6 +132,43 @@ describe('ipns', function () { expect(data.Validity).to.equalBytes(uint8ArrayFromString(expiration)) }) + it('should be able to create a record (V1+V2) with a fixed ttl', async () => { + const sequence = 0 + const ttl = BigInt(0.6e+12) + const validity = 1000000 + + const record = await ipns.create(peerId, contentPath, sequence, validity, { + ttlNs: ttl + }) + const marshalledRecord = ipns.marshal(record) + + await ipnsValidator(peerIdToRoutingKey(peerId), marshalledRecord) + + const pb = IpnsEntry.decode(marshalledRecord) + const data = parseCborData(pb.data ?? new Uint8Array(0)) + expect(data.TTL).to.equal(ttl) + }) + + it('should be able to create a record (V2) with a fixed ttl', async () => { + const sequence = 0 + const ttl = BigInt(1.6e+12) + const validity = 1000000 + + const record = await ipns.create(peerId, contentPath, sequence, validity, { + ttlNs: ttl, + v1Compatible: false + }) + const marshalledRecord = ipns.marshal(record) + + await ipnsValidator(peerIdToRoutingKey(peerId), marshalledRecord) + + const pb = IpnsEntry.decode(marshalledRecord) + expect(pb).to.not.have.property('ttl') + + const data = parseCborData(pb.data ?? new Uint8Array(0)) + expect(data.TTL).to.equal(ttl) + }) + it('should create an ipns record (V1+V2) and validate it correctly', async () => { const sequence = 0 const validity = 1000000