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:
- Click "Addressable Kinds" to fetch kinds 30023, 30024, 30078 from all relays
- Group results by
kind:d-tagpair - Populate a dropdown with all discovered pairs
- Selecting a pair shows the relay status table and event JSON using the existing UI
- 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-settingsKind 30023 - Long-form Article: my-blog-post-slugKind 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()
- Set button active state, clear UI
- Call
fetchEventsFromAllRelays({ kinds: ADDRESSABLE_KINDS, authors: [currentPubkey] }) - Group all returned events by
kind:d-tagpair - For each group, find the latest event (highest
created_at) - Store in
addressableEventGroups - Call
populateAddressableDropdown()
New Function: populateAddressableDropdown()
- Clear and populate
selAddressablewith options - Each option value =
kind:d-valuekey - Each option text =
Kind XXXXX - Label: d-tag-value(truncated) - Show
divAddressableSelector
New Function: onAddressableSelected()
- Get selected key from dropdown
- Look up group from
addressableEventGroups - Set
eventsByRelayto the group's filtered relay data - Call
populateEventListFromFetch()to show relay table - 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 objectpopulateEventListFromFetch()— works with anyeventsByRelaydataresignAndPost()— preservestagsarray which includes thedtagrepostEvent()— publishes event as-isupdateValidationStatus()— 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:
- Add the kind number to
ADDRESSABLE_KINDSarray - Add a label to
ADDRESSABLE_KIND_LABELSmap - 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