Added custom events and updated reply events handling

Implemented support for creating custom events. Also integrated functionality to generate reply events by retrieving them from relays first, with compatibility for multiple eventId formats like nevent, note, and hexadecimal strings.
This commit is contained in:
2025-11-22 11:24:50 +00:00
parent 9285f8e583
commit 59b0461bad

View File

@@ -32,18 +32,19 @@
<div class="tabs"> <div class="tabs">
<div class="tab active" data-tab="tab1">Post</div> <div class="tab active" data-tab="tab1">Post</div>
<div class="tab" data-tab="tab2">Reply</div> <div class="tab" data-tab="tab2">Reply</div>
<div class="tab" data-tab="tab3">Create Profile</div> <div class="tab" data-tab="tab3">Create/Edit Profile</div>
<div class="tab" data-tab="tab4">Custom Event</div>
</div> </div>
<div class="tab-content active" id="tab1"> <div class="tab-content active" id="tab1">
<h3>Post</h3> <h3>Post</h3>
<label for="final-content">Message Content:</label> <label for="post-content">Message Content:</label>
<textarea id="final-content" rows="3" placeholder="Enter your message content..."></textarea> <textarea id="post-content" rows="3" placeholder="Enter your message content..."></textarea>
</div> </div>
<div class="tab-content" id="tab2"> <div class="tab-content" id="tab2">
<h3>Reply</h3> <h3>Reply</h3>
<label for="nevent">Nevent:</label> <label for="reply-id">EventId/NoteId/Nevent:</label>
<textarea id="nevent" placeholder="Enter the nevent for the note..."></textarea> <textarea id="reply-id" placeholder="Enter the nevent for the note..."></textarea>
<label for="reply-content">Message Content:</label> <label for="reply-content">Message Content:</label>
<textarea id="reply-content" rows="3" placeholder="Enter your message content..."></textarea> <textarea id="reply-content" rows="3" placeholder="Enter your message content..."></textarea>
</div> </div>
@@ -67,6 +68,16 @@
<label for="lud16">Lightning Address:</label> <label for="lud16">Lightning Address:</label>
<textarea id="lud16" placeholder="Enter your lightning address..."></textarea> <textarea id="lud16" placeholder="Enter your lightning address..."></textarea>
</div> </div>
<div class="tab-content" id="tab4">
<h3>Custom Event</h3>
<label for="kind">Event Kind:</label>
<textarea id="kind" placeholder="Enter your event kind. Ex: 0, 1, 30000..."></textarea>
<label for="content">Content:</label>
<textarea id="content" rows="3" placeholder="A short bio..."></textarea>
<label for="tags">Tags:</label>
<textarea id="tags" rows="3" placeholder="Tags in format [['p', 'pubkey...'], ['e', 'event_id', wss://nos.lol, 'pubkey...']]"></textarea>
</div>
</div> </div>
<button onclick="createFinalEvent()">Create Event That Will Be Published Publicly</button> <button onclick="createFinalEvent()">Create Event That Will Be Published Publicly</button>
@@ -107,12 +118,12 @@
</div> </div>
<!-- Load the official nostr-tools bundle first --> <!-- Load the official nostr-tools bundle first -->
<!-- <script src="./nostr.bundle.js"></script> --> <script src="./nostr.bundle.js"></script>
<script src="https://laantungir.net/nostr-login-lite/nostr.bundle.js"></script> <!-- <script src="https://laantungir.net/nostr-login-lite/nostr.bundle.js"></script> -->
<!-- Load NOSTR_LOGIN_LITE main library --> <!-- Load NOSTR_LOGIN_LITE main library -->
<script src="https://laantungir.net/nostr-login-lite/nostr-lite.js"></script> <!-- <script src="https://laantungir.net/nostr-login-lite/nostr-lite.js"></script> -->
<!-- <script src="./nostr-lite.js"></script> --> <script src="./nostr-lite.js"></script>
<script> <script>
@@ -770,6 +781,79 @@
} }
} }
// Load event from id
async function loadReplyTagsForEvent(id, knownRelays) {
if (!id) return;
console.log('INFO', `Loading event`, id);
try {
const pool = new window.NostrTools.SimplePool();
const relays = [relayUrl, 'wss://relay.laantungir.net', 'wss://nos.lol', 'wss://relay.primal.net', 'wss://relay.damus.io', 'wss://relay.nostr.band'].concat(knownRelays);
// Enable tracking
pool.trackRelays = true;
// Query for an event
const events = await pool.querySync(relays, {
ids: [id],
limit: 1
});
const event = events[0];
let returnEventTags = [];
let relaysSeenOn = [];
if (event) {
const seenRelays = pool.seenOn.get(event.id);
relaysSeenOn = seenRelays ? Array.from(seenRelays).map(r => r.url) : [];
}
pool.close(relays);
if (events.length > 0) {
// event is a nostr event with tags
const refs = window.NostrTools.nip10.parse(events[0])
// get the root event of the thread
if (refs.root) {
const relay = refs.root.relays.length > 0 ? refs.root.relays[0] : '';
if (refs.root.author) {
returnEventTags.push(['e', refs.root.id, relay, 'root', refs.root.author]);
}
else {
returnEventTags.push(['e', refs.root.id, relay, 'root']);
}
returnEventTags.push(['e', id, relaysSeenOn[0], 'reply', event.pubkey]);
if (refs.root.author)
returnEventTags.push(['p', refs.root.author, relay]);
returnEventTags.push(['p', event.pubkey, relaysSeenOn[0]]);
} else {
returnEventTags.push(['e', id, relaysSeenOn[0], 'root']);
returnEventTags.push(['p', event.pubkey]);
}
// get any referenced profiles
for (let profile of refs.profiles) {
if (!returnEventTags.some(tag => tag[0] === 'p' && tag[1] === profile.pubkey)) {
if (profile.relays.length > 0) {
returnEventTags.push(['p', profile.pubkey, profile.relays[0]]);
}
else {
returnEventTags.push(['p', profile.pubkey]);
}
}
}
return [events[0], returnEventTags];
} else {
console.log('INFO', 'Event not found');
return null;
}
} catch (error) {
console.log('ERROR', `Profile loading failed: ${error.message}`);
}
}
// Create final event (kind 1) // Create final event (kind 1)
async function createFinalEvent() { async function createFinalEvent() {
// Get the active tab // Get the active tab
@@ -777,8 +861,9 @@
// Get content based on active tab // Get content based on active tab
let content = ''; let content = '';
let nevent = ''; let replyEventId = '';
let neventData; let replyEvent = {};
let replyTags = [];
let name = ''; let name = '';
let about = ''; let about = '';
let profilePic = ''; let profilePic = '';
@@ -787,14 +872,16 @@
let banner = ''; let banner = '';
let nip05 = ''; let nip05 = '';
let lud16 = ''; let lud16 = '';
let tags = '';
let kind = '';
switch(activeTab) { switch(activeTab) {
case 'tab1': // Post case 'tab1': // Post
content = document.getElementById('final-content').value.trim(); content = document.getElementById('post-content').value.trim();
break; break;
case 'tab2': // Reply case 'tab2': // Reply
content = document.getElementById('reply-content').value.trim(); content = document.getElementById('reply-content').value.trim();
nevent = document.getElementById('nevent').value.trim(); replyEventId = document.getElementById('reply-id').value.trim();
break; break;
case 'tab3': // Create Profile case 'tab3': // Create Profile
name = document.getElementById('name').value.trim(); name = document.getElementById('name').value.trim();
@@ -806,8 +893,13 @@
nip05 = document.getElementById('nip05').value.trim(); nip05 = document.getElementById('nip05').value.trim();
lud16 = document.getElementById('lud16').value.trim(); lud16 = document.getElementById('lud16').value.trim();
break; break;
case 'tab4': // Custom Event
kind = document.getElementById('kind').value.trim();
content = document.getElementById('content').value.trim();
tags = document.getElementById('tags').value.trim();
break;
} }
// Validate content based on tab // Validate content based on tab
if (activeTab === 'tab1') { if (activeTab === 'tab1') {
if (!content) { if (!content) {
@@ -819,14 +911,33 @@
alert('Please enter message content'); alert('Please enter message content');
return; return;
} }
if (!nevent.startsWith('nevent')) { let eventId = '';
alert('Please enter a valid nevent'); let knownRelays = [];
try {
if (replyEventId.startsWith('nevent')) {
const replyEventData = window.NostrTools.nip19.decode(replyEventId).data;
eventId = replyEventData.id;
knownRelays = replyEventData.relays;
} else if (replyEventId.startsWith('note')) {
eventId = window.NostrTools.nip19.decode(replyEventId).data;
} else {
eventId = replyEventId;
}
} catch (error) {
console.error(error);
alert('Error decoding nevent string', error.message);
return; return;
} }
const regex = /^[0-9a-f]{64}$/;
if (!regex.test(eventId)) {
alert('Invalid event ID');
}
try { try {
neventData = window.NostrTools.nip19.decode(nevent).data; [ replyEvent, replyTags ] = await loadReplyTagsForEvent(eventId, knownRelays);
} catch (error) { } catch (error) {
alert('Error decoding nevent string', error.message); alert('Error fetching reply event', error.message);
return; return;
} }
} else if (activeTab === 'tab3') { } else if (activeTab === 'tab3') {
@@ -834,6 +945,22 @@
alert('Please enter your name'); alert('Please enter your name');
return; return;
} }
} else if (activeTab === 'tab4') {
if (!kind) {
alert('Please enter the event kind');
return;
}
if (!/^-?\d+$/.test(kind)) {
alert("Please enter a valid integer for event kind.");
return; // Prevent form submission
}
try {
kind = Number(kind);
tags = JSON.parse(tags.replace(/'/g, '"'))
} catch (error) {
alert('Error parsing tags', error.message);
return;
}
} }
try { try {
@@ -853,12 +980,9 @@
eventTemplate = { eventTemplate = {
kind: 1, kind: 1,
content: content, content: content,
tags: [['e', neventData.id, neventData.relays[0], 'root'], ['p', neventData.author]], tags: replyTags,
created_at: Math.floor(Date.now() / 1000) created_at: Math.floor(Date.now() / 1000)
}; };
neventData.relays.slice(1).forEach(relay => {
eventTemplate.tags.push(['r', relay]);
});
break; break;
case 'tab3': // Create Profile case 'tab3': // Create Profile
@@ -878,6 +1002,15 @@
created_at: Math.floor(Date.now() / 1000) created_at: Math.floor(Date.now() / 1000)
}; };
break; break;
case 'tab4': // Create Profile
eventTemplate = {
kind: kind,
content: content,
tags: tags,
created_at: Math.floor(Date.now() / 1000)
};
break;
} }
// Your existing event publishing logic here // Your existing event publishing logic here
@@ -2084,7 +2217,7 @@
bounceCounter = 0; bounceCounter = 0;
// Clear UI elements // Clear UI elements
document.getElementById('final-content').value = ''; document.getElementById('post-content').value = '';
document.getElementById('final-event-display').textContent = ''; document.getElementById('final-event-display').textContent = '';
document.getElementById('bounces-container').innerHTML = ''; document.getElementById('bounces-container').innerHTML = '';