Files
client/plans/addressable-events-feature.md
2026-04-17 16:52:51 -04:00

6.4 KiB

Addressable Events Feature for event.html

Overview

Add an "Addressable Kinds" button to www/event.html that fetches addressable events (kinds 30023, 30024, 30078) from all relays, groups them by kind:d-tag pair, and lets the user browse, inspect, and republish them.

Problem

The current event.html handles kinds 0, 3, and 10002 (replaceable events). Addressable events (kinds 30000-39999) are different — they're keyed by the combination of kind + pubkey + d-tag. A user may have many addressable events with different d-tag values, and each relay may have different versions. There's no easy way to audit which relays have the latest version of each addressable event.

Solution

Add a new button + dropdown workflow:

  1. Click "Addressable Kinds" to fetch kinds 30023, 30024, 30078 from all relays
  2. Group results by kind:d-tag pair
  3. Populate a dropdown with all discovered pairs
  4. Selecting a pair shows the relay status table and event JSON using the existing UI
  5. User can Repost or Resign & Post to update outdated relays

Architecture

flowchart TD
    A[User clicks Addressable Kinds button] --> B[Fetch kinds 30023 + 30024 + 30078 from all relays]
    B --> C[Collect all events from all relays]
    C --> D[Group by kind:d-tag pair]
    D --> E[For each group find latest event by created_at]
    E --> F[Populate dropdown with kind:d-tag pairs]
    F --> G[User selects item from dropdown]
    G --> H[Filter eventsByRelay to only matching kind:d events]
    H --> I[Display in existing relay table and txtEventJson]
    I --> J{User action}
    J -->|Repost| K[Publish signed event as-is]
    J -->|Resign and Post| L[New timestamp + re-sign + publish]
    L --> M[d-tag preserved via tags array copy]

Target Kinds (Initial)

Kind Label NIP
30023 Long-form Article NIP-23
30024 Draft Article NIP-23
30078 App-specific Data NIP-78

These are defined in a configurable array at the top of the script for easy expansion later.

Dropdown Display Format

Each option: Kind XXXXX - Label: d-tag-value

Examples:

  • Kind 30078 - App-specific Data: my-app-settings
  • Kind 30023 - Long-form Article: my-blog-post-slug
  • Kind 30024 - Draft Article: draft-in-progress

Long d-tag values are truncated with ellipsis.

Implementation Details

File Changed

Only www/event.html — the page is self-contained with inline styles and scripts.

HTML Changes (around line 257-261)

Add after existing kind buttons:

<button id="btnAddressable" class="btnKind">Addressable Kinds</button>

Add new dropdown container between kind buttons and event list table:

<div id="divAddressableSelector" style="display: none;">
  <select id="selAddressable">
    <option value="">-- Select an addressable event --</option>
  </select>
</div>

CSS Changes

#divAddressableSelector {
  margin: 10px 0;
}

#selAddressable {
  width: 100%;
  padding: 10px;
  border: var(--border-width) solid var(--muted-color);
  border-radius: var(--border-radius);
  font-family: var(--font-family);
  font-size: 14px;
  background-color: var(--secondary-color);
  color: var(--primary-color);
  cursor: pointer;
}

JavaScript Changes

New Config (top of script section)

// Addressable event kinds to fetch
const ADDRESSABLE_KINDS = [30023, 30024, 30078];
const ADDRESSABLE_KIND_LABELS = {
  30023: 'Long-form Article',
  30024: 'Draft Article',
  30078: 'App-specific Data'
};

New Global Variables

let addressableEventGroups = new Map(); // Map<'kind:d-value', { latestEvent, eventsByRelay }>
let currentAddressableKey = null;

New Function: loadAddressableEvents()

  1. Set button active state, clear UI
  2. Call fetchEventsFromAllRelays({ kinds: ADDRESSABLE_KINDS, authors: [currentPubkey] })
  3. Group all returned events by kind:d-tag pair
  4. For each group, find the latest event (highest created_at)
  5. Store in addressableEventGroups
  6. Call populateAddressableDropdown()

New Function: populateAddressableDropdown()

  1. Clear and populate selAddressable with options
  2. Each option value = kind:d-value key
  3. Each option text = Kind XXXXX - Label: d-tag-value (truncated)
  4. Show divAddressableSelector

New Function: onAddressableSelected()

  1. Get selected key from dropdown
  2. Look up group from addressableEventGroups
  3. Set eventsByRelay to the group's filtered relay data
  4. Call populateEventListFromFetch() to show relay table
  5. Call loadEventFromData() with the latest event to show JSON and relay status

Event Handler Wiring

document.getElementById('btnAddressable').addEventListener('click', loadAddressableEvents);
document.getElementById('selAddressable').addEventListener('change', onAddressableSelected);

No Changes Needed to Existing Functions

  • loadEventFromData() — works with any event object
  • populateEventListFromFetch() — works with any eventsByRelay data
  • resignAndPost() — preserves tags array which includes the d tag
  • repostEvent() — publishes event as-is
  • updateValidationStatus() — validates any event JSON

Key Detail: d-tag Extraction

To get the d-tag value from an event:

const dTag = event.tags.find(t => t[0] === 'd');
const dValue = dTag ? dTag[1] : '';

The grouping key is: ${event.kind}:${dValue}

Future Expansion

To add more addressable kinds:

  1. Add the kind number to ADDRESSABLE_KINDS array
  2. Add a label to ADDRESSABLE_KIND_LABELS map
  3. No other changes needed

To fetch ALL addressable kinds (30000-39999), generate the array:

const ALL_ADDRESSABLE = Array.from({length: 10000}, (_, i) => 30000 + i);

Note: This creates a large filter (~60KB) that some relays may reject. Errors are handled gracefully per-relay.

Todo List

  • Add "Addressable Kinds" button to divKindButtons in HTML
  • Add dropdown select element for kind:d-tag pairs in HTML
  • Add CSS styles for the new dropdown and addressable UI elements
  • Add new global variables and config constants
  • Implement loadAddressableEvents function
  • Implement grouping logic - group events by kind:d-tag pair
  • Implement populateAddressableDropdown
  • Implement onAddressableSelected - handle dropdown change
  • Wire up button click and dropdown change event handlers
  • Verify Resign & Post preserves d-tag for addressable events
  • Test the full flow