@kehto/nip
v0.4.0
Published
Tree-shakable bundle of unique Nostr NIP utilities for napplet runtimes — each NIP at its own subpath (e.g. @kehto/nip/66)
Maintainers
Readme
@kehto/nip
A tree-shakable bundle of unique Nostr NIP utilities for napplet runtimes —
the NIPs that nostr-tools does not ship but that relay-aware runtimes
commonly need. Each NIP lives in its own folder at its own subpath, so consumers
import only what they use; the package is sideEffects: false, so bundlers drop
any NIP that isn't referenced.
NIPs
| Subpath | NIP | What it provides |
|---------|-----|------------------|
| @kehto/nip/5a | NIP-5A | aggregate hash compute/verify over path tags (computeAggregateHash, verifyAggregate) |
| @kehto/nip/5d | NIP-5D | content-addressed napplet manifest resolution — parse, verify sig + aggregate + Blossom blobs (resolveNapplet) with optional Cache Storage artifact caching |
| @kehto/nip/51 | NIP-51 | lists & sets parser — mute/bookmarks/relay-sets/emoji-sets/… (parseList) |
| @kehto/nip/65 | NIP-65 | relay-list (kind 10002) parsing + outbox/inbox resolution (createNip65Registry) |
| @kehto/nip/66 | NIP-66 | kind-30166 relay-discovery aggregator (createNip66Aggregator) |
| @kehto/nip/89 | NIP-89 | app-handler discovery (kind 31989/31990) (parseHandlerInformation) |
Each subpath has its own README with full API docs and examples (linked above).
More unique NIPs are added as their own subpath (@kehto/nip/<n>) over time.
For browser hosts that want repeated NIP-5D loads to reuse verified artifact bytes, see the repo guide: Implement a napplet artifact cache.
Selection criteria
A NIP earns a place here only if it is:
- Unique — not already provided by
nostr-tools(re-wrappingnip04,nip19,nip25,nip44,nip57, … would be a no-op package). - Broadly needed — likely required by many runtimes, not just one app.
- Substantive — handles a real common case in a widely-compatible way, with no framework coupling and no module-global state.
Usage
// Import only the NIP you need — nothing else is bundled.
import { createNip65Registry } from '@kehto/nip/65';
const registry = createNip65Registry();
registry.ingest(kind10002Event);
const outbox = registry.resolveOutboxRelays([authorPubkey]);A convenience barrel re-export is also available at the package root
(@kehto/nip), but prefer subpath imports for the smallest bundles.
Conventions
Every NIP module is:
- Pure / framework-agnostic — no Svelte/React, no DOM assumptions, no relay library baked in. Relay pools, signers, and decryptors are injected via small interfaces.
- Multi-instance safe — stateful helpers are closure-scoped factories
(
create*), never module globals, so multiple runtimes in one process never alias each other. - Fully documented — all public exports carry JSDoc with
@param,@returns, and@example.
Adding a NIP
- Create
src/<n>/index.tsimplementing the NIP utility (framework-agnostic, no module-global state, inject relay/pool/crypto concerns via interfaces). - Add
src/<n>/index.test.tswith unit tests andsrc/<n>/README.mdwith API docs. - Add
src/<n>/index.tsto thetsupentryarray and a./<n>entry toexportsinpackage.json. - Re-export it from
src/index.tsfor the barrel, and add the@kehto/nip/<n>alias to the repovitest.config.ts. - Add a row to the table above.
