Skip to content

NIP Support

Event Classification

Event TypeKind Rangestore.add() Behavior
Regular1-9999 (excluding below)Stored as-is
Replaceable0, 3, 10000-19999Only latest by (pubkey, kind) kept
Addressable30000-39999Only latest by (kind, pubkey, d-tag) kept
Ephemeral20000-29999Rejected (not stored)

Supported NIPs

NIPFeatureImplementation
NIP-01Event kinds, filters, tag queriesnip-rules.ts, filter-matcher.ts
NIP-01Replaceable events (kind 0, 3, 10000-19999)store.add() step 5
NIP-01Addressable events (kind 30000-39999)store.add() step 6, d-tag "" fallback
NIP-09Event deletion (kind 5)store.add() step 4, e-tag + a-tag
NIP-09Pubkey verification on deletionAuthor match required
NIP-09Pending deletions (out-of-order arrival)pendingDeletions Map with TTL
NIP-33Parameterized replaceable eventsMerged into NIP-01 addressable handling
NIP-40Event expirationisExpired() check on add + query

Replacement Rules

When a new event arrives for the same replaceable/addressable key:

  1. Compare created_at — higher wins
  2. Tiebreaker: lower event id (lexicographic) wins
  3. Loser is discarded (not stored)

Deletion Flow

Online (during subscription)

kind:5 arrives → extract e-tags and a-tags
  → For each e-tag: find target in store, verify pubkey match → mark deleted
  → For each a-tag: find addressable event, verify pubkey + created_at → mark deleted
  → Target not found → register in pendingDeletions (TTL: 5min, max: 10000)

Pending (target arrives later)

Regular event arrives → check pendingDeletions
  → Match found + pubkey verified → mark deleted immediately
  → No match → store normally

Startup Reconciliation

typescript
connectStore(rxNostr, store, { reconcileDeletions: true });
// Fetches kind:5 events for all cached event IDs (chunked by 50)

Tag Indexing

All single-letter tags are indexed by default (NIP-01 compliant). Restrict with:

typescript
createEventStore({
  backend: memoryBackend(),
  indexedTags: ['e', 'p', 't', 'a', 'k'], // only these tags
});

MIT License