@helia/ipns 10.1.1-b34bc7c7 → 10.2.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.
Files changed (61) hide show
  1. package/README.md +40 -0
  2. package/dist/index.min.js +5 -5
  3. package/dist/index.min.js.map +4 -4
  4. package/dist/src/errors.d.ts +11 -0
  5. package/dist/src/errors.d.ts.map +1 -1
  6. package/dist/src/errors.js +13 -0
  7. package/dist/src/errors.js.map +1 -1
  8. package/dist/src/index.d.ts +136 -7
  9. package/dist/src/index.d.ts.map +1 -1
  10. package/dist/src/index.js +41 -0
  11. package/dist/src/index.js.map +1 -1
  12. package/dist/src/ipns/publisher.d.ts +3 -3
  13. package/dist/src/ipns/publisher.d.ts.map +1 -1
  14. package/dist/src/ipns/publisher.js +17 -18
  15. package/dist/src/ipns/publisher.js.map +1 -1
  16. package/dist/src/ipns/republisher.d.ts +6 -1
  17. package/dist/src/ipns/republisher.d.ts.map +1 -1
  18. package/dist/src/ipns/republisher.js +157 -24
  19. package/dist/src/ipns/republisher.js.map +1 -1
  20. package/dist/src/ipns/resolver.d.ts +13 -1
  21. package/dist/src/ipns/resolver.d.ts.map +1 -1
  22. package/dist/src/ipns/resolver.js +40 -31
  23. package/dist/src/ipns/resolver.js.map +1 -1
  24. package/dist/src/ipns.d.ts +6 -3
  25. package/dist/src/ipns.d.ts.map +1 -1
  26. package/dist/src/ipns.js +12 -3
  27. package/dist/src/ipns.js.map +1 -1
  28. package/dist/src/local-store.d.ts +5 -0
  29. package/dist/src/local-store.d.ts.map +1 -1
  30. package/dist/src/local-store.js +68 -23
  31. package/dist/src/local-store.js.map +1 -1
  32. package/dist/src/pb/metadata.d.ts +14 -1
  33. package/dist/src/pb/metadata.d.ts.map +1 -1
  34. package/dist/src/pb/metadata.js +35 -2
  35. package/dist/src/pb/metadata.js.map +1 -1
  36. package/dist/src/routing/index.d.ts +13 -1
  37. package/dist/src/routing/index.d.ts.map +1 -1
  38. package/dist/src/routing/index.js +17 -0
  39. package/dist/src/routing/index.js.map +1 -1
  40. package/dist/src/utils.d.ts +5 -0
  41. package/dist/src/utils.d.ts.map +1 -1
  42. package/dist/src/utils.js +18 -0
  43. package/dist/src/utils.js.map +1 -1
  44. package/dist/src/validator.d.ts +6 -0
  45. package/dist/src/validator.d.ts.map +1 -1
  46. package/dist/src/validator.js +24 -14
  47. package/dist/src/validator.js.map +1 -1
  48. package/dist/typedoc-urls.json +90 -0
  49. package/package.json +2 -2
  50. package/src/errors.ts +18 -0
  51. package/src/index.ts +145 -7
  52. package/src/ipns/publisher.ts +22 -20
  53. package/src/ipns/republisher.ts +182 -26
  54. package/src/ipns/resolver.ts +54 -36
  55. package/src/ipns.ts +20 -6
  56. package/src/local-store.ts +77 -22
  57. package/src/pb/metadata.proto +10 -0
  58. package/src/pb/metadata.ts +44 -3
  59. package/src/routing/index.ts +30 -1
  60. package/src/utils.ts +19 -0
  61. package/src/validator.ts +30 -18
@@ -0,0 +1,90 @@
1
+ {
2
+ "codec": "https://ipfs.github.io/helia/functions/_helia_ipns.IPNSEntry.ValidityType.codec.html",
3
+ "ValidityType": "https://ipfs.github.io/helia/enums/_helia_ipns.IPNSEntry.ValidityType.html",
4
+ "IPNSEntryDataFieldEvent": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSEntry.IPNSEntryDataFieldEvent.html",
5
+ "IPNSEntryPublicKeyFieldEvent": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSEntry.IPNSEntryPublicKeyFieldEvent.html",
6
+ "IPNSEntrySequenceFieldEvent": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSEntry.IPNSEntrySequenceFieldEvent.html",
7
+ "IPNSEntrySignatureV1FieldEvent": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSEntry.IPNSEntrySignatureV1FieldEvent.html",
8
+ "IPNSEntrySignatureV2FieldEvent": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSEntry.IPNSEntrySignatureV2FieldEvent.html",
9
+ "IPNSEntryTtlFieldEvent": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSEntry.IPNSEntryTtlFieldEvent.html",
10
+ "IPNSEntryValidityFieldEvent": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSEntry.IPNSEntryValidityFieldEvent.html",
11
+ "IPNSEntryValidityTypeFieldEvent": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSEntry.IPNSEntryValidityTypeFieldEvent.html",
12
+ "IPNSEntryValueFieldEvent": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSEntry.IPNSEntryValueFieldEvent.html",
13
+ "decode": "https://ipfs.github.io/helia/functions/_helia_ipns.IPNSEntry.decode.html",
14
+ "encode": "https://ipfs.github.io/helia/functions/_helia_ipns.IPNSEntry.encode.html",
15
+ "stream": "https://ipfs.github.io/helia/functions/_helia_ipns.IPNSEntry.stream.html",
16
+ "InvalidEmbeddedPublicKeyError": "https://ipfs.github.io/helia/classes/_helia_ipns.InvalidEmbeddedPublicKeyError.html",
17
+ "InvalidRecordDataError": "https://ipfs.github.io/helia/classes/_helia_ipns.InvalidRecordDataError.html",
18
+ "InvalidTopicError": "https://ipfs.github.io/helia/classes/_helia_ipns.InvalidTopicError.html",
19
+ "InvalidValueError": "https://ipfs.github.io/helia/classes/_helia_ipns.InvalidValueError.html",
20
+ "RecordExpiredError": "https://ipfs.github.io/helia/classes/_helia_ipns.RecordExpiredError.html",
21
+ "RecordNotFoundError": "https://ipfs.github.io/helia/classes/_helia_ipns.RecordNotFoundError.html",
22
+ "RecordObsoleteError": "https://ipfs.github.io/helia/classes/_helia_ipns.RecordObsoleteError.html",
23
+ "RecordsFailedValidationError": "https://ipfs.github.io/helia/classes/_helia_ipns.RecordsFailedValidationError.html",
24
+ "RecordTooLargeError": "https://ipfs.github.io/helia/classes/_helia_ipns.RecordTooLargeError.html",
25
+ "SignatureCreationError": "https://ipfs.github.io/helia/classes/_helia_ipns.SignatureCreationError.html",
26
+ "SignatureVerificationError": "https://ipfs.github.io/helia/classes/_helia_ipns.SignatureVerificationError.html",
27
+ "UnsupportedValidityError": "https://ipfs.github.io/helia/classes/_helia_ipns.UnsupportedValidityError.html",
28
+ "CreateIPNSRecordOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.CreateIPNSRecordOptions.html",
29
+ "IPNS": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNS.html",
30
+ ".:IPNS": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNS.html",
31
+ "IPNSComponents": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSComponents.html",
32
+ ".:IPNSComponents": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSComponents.html",
33
+ "IPNSEntry": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSEntry.html",
34
+ "IPNSOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSOptions.html",
35
+ ".:IPNSOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSOptions.html",
36
+ "IPNSPublishResult": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSPublishResult.html",
37
+ ".:IPNSPublishResult": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSPublishResult.html",
38
+ "IPNSRecordData": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSRecordData.html",
39
+ ".:IPNSRecordData": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSRecordData.html",
40
+ "IPNSResolveOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSResolveOptions.html",
41
+ ".:IPNSResolveOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSResolveOptions.html",
42
+ "IPNSResolver": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSResolver.html",
43
+ ".:IPNSResolver": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSResolver.html",
44
+ "IPNSResolveResult": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSResolveResult.html",
45
+ ".:IPNSResolveResult": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSResolveResult.html",
46
+ "IPNSResolverOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSResolverOptions.html",
47
+ ".:IPNSResolverOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSResolverOptions.html",
48
+ "IPNSRouting": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSRouting.html",
49
+ "IPNSRoutingGetOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSRoutingGetOptions.html",
50
+ "IPNSRoutingPutOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.IPNSRoutingPutOptions.html",
51
+ "PublishOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.PublishOptions.html",
52
+ ".:PublishOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.PublishOptions.html",
53
+ "PublishResult": "https://ipfs.github.io/helia/interfaces/_helia_ipns.PublishResult.html",
54
+ "PubSub": "https://ipfs.github.io/helia/interfaces/_helia_ipns.PubSub.html",
55
+ "PubSubEvents": "https://ipfs.github.io/helia/interfaces/_helia_ipns.PubSubEvents.html",
56
+ "PubSubMessage": "https://ipfs.github.io/helia/interfaces/_helia_ipns.PubSubMessage.html",
57
+ "PubsubRoutingComponents": "https://ipfs.github.io/helia/interfaces/_helia_ipns.PubsubRoutingComponents.html",
58
+ "PubSubSubscription": "https://ipfs.github.io/helia/interfaces/_helia_ipns.PubSubSubscription.html",
59
+ "PubSubSubscriptionChangeData": "https://ipfs.github.io/helia/interfaces/_helia_ipns.PubSubSubscriptionChangeData.html",
60
+ "RepublishOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.RepublishOptions.html",
61
+ ".:RepublishOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.RepublishOptions.html",
62
+ "RepublishResult": "https://ipfs.github.io/helia/interfaces/_helia_ipns.RepublishResult.html",
63
+ ".:RepublishResult": "https://ipfs.github.io/helia/interfaces/_helia_ipns.RepublishResult.html",
64
+ "UnpublishOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.UnpublishOptions.html",
65
+ ".:UnpublishOptions": "https://ipfs.github.io/helia/interfaces/_helia_ipns.UnpublishOptions.html",
66
+ "DatastoreProgressEvents": "https://ipfs.github.io/helia/types/_helia_ipns.DatastoreProgressEvents.html",
67
+ ".:DatastoreProgressEvents": "https://ipfs.github.io/helia/types/_helia_ipns.DatastoreProgressEvents.html",
68
+ "HeliaRoutingProgressEvents": "https://ipfs.github.io/helia/types/_helia_ipns.HeliaRoutingProgressEvents.html",
69
+ "IPNSRoutingProgressEvents": "https://ipfs.github.io/helia/types/_helia_ipns.IPNSRoutingProgressEvents.html",
70
+ "PublishProgressEvents": "https://ipfs.github.io/helia/types/_helia_ipns.PublishProgressEvents.html",
71
+ ".:PublishProgressEvents": "https://ipfs.github.io/helia/types/_helia_ipns.PublishProgressEvents.html",
72
+ "PubSubProgressEvents": "https://ipfs.github.io/helia/types/_helia_ipns.PubSubProgressEvents.html",
73
+ "ResolveProgressEvents": "https://ipfs.github.io/helia/types/_helia_ipns.ResolveProgressEvents.html",
74
+ ".:ResolveProgressEvents": "https://ipfs.github.io/helia/types/_helia_ipns.ResolveProgressEvents.html",
75
+ "UpkeepPolicy": "https://ipfs.github.io/helia/types/_helia_ipns.UpkeepPolicy.html",
76
+ ".:UpkeepPolicy": "https://ipfs.github.io/helia/types/_helia_ipns.UpkeepPolicy.html",
77
+ "createIPNSRecord": "https://ipfs.github.io/helia/functions/_helia_ipns.createIPNSRecord.html",
78
+ "heliaIPNSRouting": "https://ipfs.github.io/helia/functions/_helia_ipns.heliaIPNSRouting.html",
79
+ "ipns": "https://ipfs.github.io/helia/functions/_helia_ipns.ipns.html",
80
+ ".:ipns": "https://ipfs.github.io/helia/functions/_helia_ipns.ipns.html",
81
+ "ipnsResolver": "https://ipfs.github.io/helia/functions/_helia_ipns.ipnsResolver.html",
82
+ ".:ipnsResolver": "https://ipfs.github.io/helia/functions/_helia_ipns.ipnsResolver.html",
83
+ "ipnsSelector": "https://ipfs.github.io/helia/functions/_helia_ipns.ipnsSelector.html",
84
+ "ipnsValidator": "https://ipfs.github.io/helia/functions/_helia_ipns.ipnsValidator.html",
85
+ "isLocalStoreRouting": "https://ipfs.github.io/helia/functions/_helia_ipns.isLocalStoreRouting.html",
86
+ "multihashFromIPNSRoutingKey": "https://ipfs.github.io/helia/functions/_helia_ipns.multihashFromIPNSRoutingKey.html",
87
+ "multihashToIPNSRoutingKey": "https://ipfs.github.io/helia/functions/_helia_ipns.multihashToIPNSRoutingKey.html",
88
+ "pubSubIPNSRouting": "https://ipfs.github.io/helia/functions/_helia_ipns.pubSubIPNSRouting.html",
89
+ "routerName": "https://ipfs.github.io/helia/functions/_helia_ipns.routerName.html"
90
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helia/ipns",
3
- "version": "10.1.1-b34bc7c7",
3
+ "version": "10.2.0",
4
4
  "description": "An implementation of IPNS for Helia",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "homepage": "https://github.com/ipfs/helia/tree/main/packages/ipns#readme",
@@ -50,7 +50,7 @@
50
50
  "test:electron-main": "aegir test -t electron-main"
51
51
  },
52
52
  "dependencies": {
53
- "@helia/interface": "7.1.1-b34bc7c7",
53
+ "@helia/interface": "^7.1.1",
54
54
  "@ipld/dag-cbor": "^10.0.1",
55
55
  "@ipshipyard/crypto": "^1.1.0",
56
56
  "@ipshipyard/keychain": "^1.0.2",
package/src/errors.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { IPNSEntry } from './pb/ipns.ts'
2
+
1
3
  export class RecordsFailedValidationError extends Error {
2
4
  static name = 'RecordsFailedValidationError'
3
5
  name = 'RecordsFailedValidationError'
@@ -18,6 +20,22 @@ export class RecordNotFoundError extends Error {
18
20
  name = 'RecordNotFoundError'
19
21
  }
20
22
 
23
+ export class RecordObsoleteError extends Error {
24
+ static name = 'RecordObsoleteError'
25
+ name = 'RecordObsoleteError'
26
+ /**
27
+ * The more suitable record that made the one being imported or republished
28
+ * obsolete.
29
+ */
30
+ readonly record: IPNSEntry
31
+
32
+ constructor (message: string, record: IPNSEntry) {
33
+ super(message)
34
+
35
+ this.record = record
36
+ }
37
+ }
38
+
21
39
  export class SignatureCreationError extends Error {
22
40
  static name = 'SignatureCreationError'
23
41
  name = 'SignatureCreationError'
package/src/index.ts CHANGED
@@ -135,6 +135,46 @@
135
135
  * console.info(result.record.value)
136
136
  * }
137
137
  * ```
138
+ *
139
+ * @example Republishing an existing IPNS record
140
+ *
141
+ * It is sometimes useful to be able to republish an existing IPNS record
142
+ * without needing the private key. This allows you to extend the availability
143
+ * of a record that was created elsewhere.
144
+ *
145
+ * There should be only one republisher per IPNS key. Multiple machines
146
+ * republishing the same key flood the routers with redundant writes.
147
+ *
148
+ * ```TypeScript
149
+ * import { createHelia } from 'helia'
150
+ * import { ipns } from '@helia/ipns'
151
+ * import { delegatedRoutingV1HttpApiClient } from '@helia/delegated-routing-v1-http-api-client'
152
+ * import { defaultLogger } from 'birnam'
153
+ * import { CID } from 'multiformats/cid'
154
+ *
155
+ * const helia = await createHelia()
156
+ * const name = ipns(helia)
157
+ *
158
+ * const ipnsName = 'k51qzi5uqu5dktsyfv7xz8h631pri4ct7osmb43nibxiojpttxzoft6hdyyzg4'
159
+ * const parsedCid: CID<unknown, 114, 0 | 18, 1> = CID.parse(ipnsName)
160
+ * const delegatedClient = delegatedRoutingV1HttpApiClient({
161
+ * url: 'https://delegated-ipfs.dev'
162
+ * })({
163
+ * logger: defaultLogger()
164
+ * })
165
+ * const record = await delegatedClient.getIPNS(parsedCid)
166
+ *
167
+ * // import the record into the local store (validates and stores it locally,
168
+ * // but does not publish it to the routers)
169
+ * await name.import(parsedCid, record)
170
+ *
171
+ * // start republishing it; throws RecordObsoleteError if the routers
172
+ * // already have a newer record for this key
173
+ * const { record: latestRecord } = await name.republish(parsedCid)
174
+ *
175
+ * // stop republishing a key
176
+ * await name.unpublish(parsedCid)
177
+ * ```
138
178
  */
139
179
 
140
180
  import { CID } from 'multiformats/cid'
@@ -155,6 +195,7 @@ import type { ProgressEvent, ProgressOptions } from 'progress-events'
155
195
 
156
196
  export * from './routing/index.ts'
157
197
  export * from './pb/ipns.ts'
198
+ export * from './errors.ts'
158
199
 
159
200
  export {
160
201
  multihashFromIPNSRoutingKey,
@@ -184,6 +225,14 @@ export type DatastoreProgressEvents =
184
225
  ProgressEvent<'ipns:routing:datastore:list'> |
185
226
  ProgressEvent<'ipns:routing:datastore:error', Error>
186
227
 
228
+ /**
229
+ * The automated upkeep policy for a stored IPNS record. `republish()` accepts
230
+ * every policy except `reissue`, which needs the private key to re-sign.
231
+ *
232
+ * These strings must match the `Upkeep` enum values in `pb/metadata.proto`.
233
+ */
234
+ export type UpkeepPolicy = 'reissue' | 'rebroadcast' | 'none'
235
+
187
236
  export interface PublishOptions extends AbortOptions, ProgressOptions<PublishProgressEvents | IPNSRoutingProgressEvents> {
188
237
  /**
189
238
  * Time duration of the signature validity in ms - after this many ms have
@@ -219,6 +268,17 @@ export interface PublishOptions extends AbortOptions, ProgressOptions<PublishPro
219
268
  */
220
269
  ttl?: number
221
270
 
271
+ /**
272
+ * Automated record upkeep policy.
273
+ *
274
+ * - `reissue`: re-sign the record with a new validity
275
+ * - `rebroadcast`: re-publish the existing record until it expires
276
+ * - `none`: disable automated publishing
277
+ *
278
+ * @default 'reissue'
279
+ */
280
+ upkeep?: UpkeepPolicy
281
+
222
282
  /**
223
283
  * Extensible data that will be added to the IPNS record data and signed to
224
284
  * verify it's integrity.
@@ -273,6 +333,43 @@ export interface IPNSResolveOptions extends AbortOptions, ProgressOptions<Resolv
273
333
  validate?: boolean
274
334
  }
275
335
 
336
+ export interface RepublishOptions extends AbortOptions, ProgressOptions<IPNSRoutingProgressEvents> {
337
+ /**
338
+ * Skip resolution of latest record before republishing.
339
+ *
340
+ * It's important to resolve the latest record before republishing to routers
341
+ *
342
+ * Resolution should only be skipped when confident the latest record is
343
+ * already known.
344
+ *
345
+ * @default false
346
+ */
347
+ skipResolution?: boolean
348
+
349
+ /**
350
+ * Automated record upkeep policy.
351
+ *
352
+ * Defaults to `rebroadcast` since `republish()` cannot sign new records
353
+ * without the private key.
354
+ *
355
+ * - `rebroadcast`: re-publish the existing record until it expires
356
+ * - `none`: disable automated publishing
357
+ *
358
+ * @default 'rebroadcast'
359
+ */
360
+ upkeep?: Exclude<UpkeepPolicy, 'reissue'>
361
+ }
362
+
363
+ export interface UnpublishOptions extends AbortOptions {
364
+ /**
365
+ * Also delete the record from the local store, so the node stops serving it
366
+ * immediately instead of keeping it until it expires.
367
+ *
368
+ * @default false
369
+ */
370
+ removeRecord?: boolean
371
+ }
372
+
276
373
  export interface IPNSResolveResult {
277
374
  /**
278
375
  * The resolved record
@@ -302,6 +399,18 @@ export interface IPNSPublishResult {
302
399
  publicKey: PublicKey
303
400
  }
304
401
 
402
+ export interface RepublishResult {
403
+ /**
404
+ * The published record
405
+ */
406
+ record: IPNSEntry
407
+
408
+ /**
409
+ * The public key that the record is published under
410
+ */
411
+ publicKey: PublicKey
412
+ }
413
+
305
414
  export interface IPNSResolver {
306
415
  /**
307
416
  * Accepts a CID with the libp2p-key codec and either the identity hash (for
@@ -345,7 +454,7 @@ export interface IPNS {
345
454
  * signal: AbortSignal.timeout(5_000)
346
455
  * })
347
456
  *
348
- * console.info(result) // { answer: ... }
457
+ * console.info(result) // { record, name, publicKey }
349
458
  * ```
350
459
  */
351
460
  publish(keyName: string, value: CID | PublicKey | MultihashDigest | string, options?: PublishOptions): Promise<IPNSPublishResult>
@@ -357,17 +466,46 @@ export interface IPNS {
357
466
  * (e.g. the value can be parsed as a string that does not start with
358
467
  * `/ipns/`).
359
468
  */
360
- resolve(name: CID | PublicKey | MultihashDigest | string, options?: IPNSResolveOptions): AsyncGenerator<IPNSResolveResult>
469
+ resolve(name: CID<unknown, 0x72> | PublicKey | MultihashDigest | string, options?: IPNSResolveOptions): AsyncGenerator<IPNSResolveResult>
470
+
471
+ /**
472
+ * Stop automatically republishing an IPNS record
473
+ *
474
+ * By default this removes only the republishing metadata, keeping the record
475
+ * in the datastore so it is still served until it expires. Pass
476
+ * `removeRecord: true` to also delete the record so the node stops serving it.
477
+ * If a key name is passed, the key remains in the keychain.
478
+ */
479
+ unpublish(key: CID<unknown, 0x72> | PublicKey | MultihashDigest | string, options?: UnpublishOptions): Promise<void>
480
+
481
+ /**
482
+ * Republish the record already in the local store, setting its upkeep policy.
483
+ *
484
+ * Sets the record's upkeep policy to `options.upkeep` (default `rebroadcast`)
485
+ * so the background republisher keeps it available on the routers.
486
+ *
487
+ * @throws {NotFoundError} when there is no local record to republish
488
+ * @throws {RecordObsoleteError} when the routers already have a newer record
489
+ */
490
+ republish(key: CID<unknown, 0x72> | PublicKey | MultihashDigest | string, options?: RepublishOptions): Promise<RepublishResult>
361
491
 
362
492
  /**
363
- * Stop republishing of an IPNS record.
493
+ * Import an existing IPNS record into the local store without publishing it.
494
+ *
495
+ * The record is validated and stored so this node serves it on a GET, but it
496
+ * is not broadcast to the routers. A newly imported record (for a key with no
497
+ * existing upkeep policy) is not automatically republished; call `republish`
498
+ * with an upkeep policy to start keeping it alive.
364
499
  *
365
- * This will delete the last signed IPNS record from the datastore.
500
+ * Overwrites an older record already stored under this key, or rejects with
501
+ * `RecordObsoleteError` if the stored record is newer. Importing never changes
502
+ * the key's upkeep metadata, so a key that already has an upkeep policy keeps
503
+ * it and continues to be republished automatically.
366
504
  *
367
- * Note that the record may still be resolved by other peers until it expires
368
- * or is otherwise no longer valid.
505
+ * @throws {RecordExpiredError} (or another validation error) when the record fails validation
506
+ * @throws {RecordObsoleteError} when the stored record is more suitable than the one being imported
369
507
  */
370
- unpublish(keyName: string, options?: AbortOptions): Promise<void>
508
+ import(key: CID<unknown, 0x72> | PublicKey | MultihashDigest | string, record: IPNSEntry | Uint8Array, options?: AbortOptions): Promise<void>
371
509
  }
372
510
 
373
511
  export interface IPNSComponents {
@@ -2,9 +2,10 @@ import { base36 } from 'multiformats/bases/base36'
2
2
  import { CustomProgressEvent } from 'progress-events'
3
3
  import { DEFAULT_LIFETIME_MS } from '../constants.ts'
4
4
  import { IPNSEntry } from '../pb/ipns.ts'
5
+ import { Upkeep } from '../pb/metadata.ts'
5
6
  import { createIPNSRecord } from '../records.ts'
6
7
  import { decodeExtensibleData, multihashToIPNSRoutingKey } from '../utils.ts'
7
- import type { IPNSPublishResult, PublishOptions } from '../index.ts'
8
+ import type { IPNSPublishResult, PublishOptions, UnpublishOptions } from '../index.ts'
8
9
  import type { LocalStore } from '../local-store.ts'
9
10
  import type { IPNSRouting } from '../routing/index.ts'
10
11
  import type { Keychain, PrivateKey, PublicKey } from '@helia/interface'
@@ -58,25 +59,14 @@ export class IPNSPublisher {
58
59
  })
59
60
  const marshaledRecord = IPNSEntry.encode(record)
60
61
 
62
+ const metadata = { keyName, lifetime, upkeep: Upkeep[options.upkeep ?? 'reissue'] }
61
63
  if (options.offline === true) {
62
64
  // only store record locally
63
- await this.localStore.put(routingKey, marshaledRecord, {
64
- ...options,
65
- metadata: {
66
- keyName,
67
- lifetime
68
- }
69
- })
65
+ await this.localStore.put(routingKey, marshaledRecord, { ...options, metadata })
70
66
  } else {
71
67
  // publish record to routing (including the local store)
72
68
  await Promise.all(this.routers.map(async r => {
73
- await r.put(routingKey, marshaledRecord, {
74
- ...options,
75
- metadata: {
76
- keyName,
77
- lifetime
78
- }
79
- })
69
+ await r.put(routingKey, marshaledRecord, { ...options, metadata })
80
70
  }))
81
71
  }
82
72
 
@@ -108,10 +98,22 @@ export class IPNSPublisher {
108
98
  }
109
99
  }
110
100
 
111
- async unpublish (keyName: string, options?: AbortOptions): Promise<void> {
112
- const key = await this.keychain.exportKey(keyName, options)
113
- const digest = key.publicKey.toMultihash()
114
- const routingKey = multihashToIPNSRoutingKey(digest)
115
- await this.localStore.delete(routingKey, options)
101
+ async unpublish (keyName: string | MultihashDigest, options?: UnpublishOptions): Promise<void> {
102
+ if (typeof keyName === 'string') {
103
+ const key = await this.keychain.exportKey(keyName, options)
104
+ keyName = key.publicKey.toMultihash()
105
+ }
106
+
107
+ const routingKey = multihashToIPNSRoutingKey(keyName)
108
+
109
+ if (options?.removeRecord === true) {
110
+ // delete the record and its metadata so this node stops serving it
111
+ await this.localStore.delete(routingKey, options)
112
+ return
113
+ }
114
+
115
+ // remove only the metadata so the record is still served but no longer
116
+ // automatically republished; it expires naturally at its validity
117
+ await this.localStore.deleteMetadata(routingKey, options)
116
118
  }
117
119
  }