.
This commit is contained in:
@@ -342,6 +342,7 @@
|
||||
<div class="panelTitle">Kinds</div>
|
||||
<div class="btnRow">
|
||||
<button id="btnRefreshKinds" class="btnMini" type="button">Refresh Cache</button>
|
||||
<button id="btnGetAllEvents" class="btnMini" type="button">Get all events</button>
|
||||
</div>
|
||||
<div id="divKindsStatus" class="hint">Loading...</div>
|
||||
<div id="divKindsList" class="listWrap"></div>
|
||||
@@ -683,6 +684,9 @@
|
||||
let selectedKindSub = null;
|
||||
let currentDetailEvent = null;
|
||||
let lastDecryptResult = null;
|
||||
let allEventsFetchSub = null;
|
||||
let allEventsFetchInFlight = false;
|
||||
let allEventsFetchTimeoutId = null;
|
||||
|
||||
const eventsByKind = new Map(); // kind -> Map(eventKey, event)
|
||||
const selectedEventKeys = new Set();
|
||||
@@ -703,6 +707,7 @@
|
||||
const divFooterRight = document.getElementById('divFooterRight');
|
||||
|
||||
const btnRefreshKinds = document.getElementById('btnRefreshKinds');
|
||||
const btnGetAllEvents = document.getElementById('btnGetAllEvents');
|
||||
const divKindsStatus = document.getElementById('divKindsStatus');
|
||||
const divKindsList = document.getElementById('divKindsList');
|
||||
|
||||
@@ -1396,16 +1401,22 @@
|
||||
};
|
||||
}
|
||||
|
||||
function getCachedKindsAndEventTotals() {
|
||||
const kinds = getKindsSorted();
|
||||
const totalEvents = kinds.reduce((sum, k) => sum + getEventsForKind(k).length, 0);
|
||||
return { kindsCount: kinds.length, totalEvents };
|
||||
}
|
||||
|
||||
function renderKinds() {
|
||||
const kinds = getKindsSorted();
|
||||
if (!kinds.length) {
|
||||
divKindsList.innerHTML = '<div class="hint">No cached events found.</div>';
|
||||
divKindsStatus.textContent = '0 kinds · 0 events';
|
||||
if (!allEventsFetchInFlight) divKindsStatus.textContent = '0 kinds · 0 events';
|
||||
return;
|
||||
}
|
||||
|
||||
const totalEvents = kinds.reduce((sum, k) => sum + getEventsForKind(k).length, 0);
|
||||
divKindsStatus.textContent = `${kinds.length} kinds · ${totalEvents.toLocaleString()} cached events`;
|
||||
if (!allEventsFetchInFlight) divKindsStatus.textContent = `${kinds.length} kinds · ${totalEvents.toLocaleString()} cached events`;
|
||||
|
||||
divKindsList.innerHTML = kinds.map((kind) => {
|
||||
const count = getEventsForKind(kind).length;
|
||||
@@ -1682,6 +1693,63 @@
|
||||
selectedKindSub = subscribe({ kinds: [Number(kind)], authors: [currentPubkey], limit: 500 }, { closeOnEose: false, cacheUsage: 'CACHE_FIRST' });
|
||||
}
|
||||
|
||||
function clearAllEventsFetchTimeout() {
|
||||
if (allEventsFetchTimeoutId) {
|
||||
clearTimeout(allEventsFetchTimeoutId);
|
||||
allEventsFetchTimeoutId = null;
|
||||
}
|
||||
}
|
||||
|
||||
function closeAllEventsFetchSubscription() {
|
||||
try {
|
||||
if (allEventsFetchSub && typeof allEventsFetchSub.close === 'function') allEventsFetchSub.close();
|
||||
} catch (_error) { }
|
||||
allEventsFetchSub = null;
|
||||
}
|
||||
|
||||
function finalizeGetAllEventsFetch(statusText) {
|
||||
clearAllEventsFetchTimeout();
|
||||
closeAllEventsFetchSubscription();
|
||||
allEventsFetchInFlight = false;
|
||||
if (btnGetAllEvents) btnGetAllEvents.disabled = false;
|
||||
if (statusText) {
|
||||
divKindsStatus.textContent = statusText;
|
||||
} else {
|
||||
const { kindsCount, totalEvents } = getCachedKindsAndEventTotals();
|
||||
divKindsStatus.textContent = `${kindsCount} kinds · ${totalEvents.toLocaleString()} cached events`;
|
||||
}
|
||||
}
|
||||
|
||||
async function runOneShotGetAllEventsFetch() {
|
||||
if (allEventsFetchInFlight) return;
|
||||
if (!currentPubkey) {
|
||||
divKindsStatus.textContent = 'Get all events failed: user pubkey unavailable';
|
||||
return;
|
||||
}
|
||||
|
||||
allEventsFetchInFlight = true;
|
||||
if (btnGetAllEvents) btnGetAllEvents.disabled = true;
|
||||
|
||||
const beforeTotals = getCachedKindsAndEventTotals();
|
||||
divKindsStatus.textContent = `Getting all events from relays for ${shortHex(currentPubkey)}...`;
|
||||
|
||||
try {
|
||||
closeAllEventsFetchSubscription();
|
||||
allEventsFetchSub = subscribe(
|
||||
{ authors: [currentPubkey] },
|
||||
{ closeOnEose: true, cacheUsage: 'CACHE_FIRST' }
|
||||
);
|
||||
|
||||
allEventsFetchTimeoutId = setTimeout(() => {
|
||||
const afterTotals = getCachedKindsAndEventTotals();
|
||||
const added = Math.max(0, afterTotals.totalEvents - beforeTotals.totalEvents);
|
||||
finalizeGetAllEventsFetch(`Get all events timed out · +${added.toLocaleString()} events (${afterTotals.totalEvents.toLocaleString()} total)`);
|
||||
}, 30000);
|
||||
} catch (error) {
|
||||
finalizeGetAllEventsFetch(`Get all events failed: ${error?.message || String(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function selectKind(kind, options = {}) {
|
||||
const { autoRefresh = true } = options;
|
||||
|
||||
@@ -1992,6 +2060,8 @@
|
||||
});
|
||||
|
||||
logoutButton?.addEventListener('click', async () => {
|
||||
closeAllEventsFetchSubscription();
|
||||
clearAllEventsFetchTimeout();
|
||||
try { await logout(); } catch (error) { console.error('[event-management.html] logout failed', error); }
|
||||
});
|
||||
|
||||
@@ -2004,6 +2074,10 @@
|
||||
}
|
||||
});
|
||||
|
||||
btnGetAllEvents?.addEventListener('click', async () => {
|
||||
await runOneShotGetAllEventsFetch();
|
||||
});
|
||||
|
||||
inpEventSearch.addEventListener('input', renderEvents);
|
||||
chkShowSuperseded?.addEventListener('change', renderEvents);
|
||||
|
||||
@@ -2319,6 +2393,15 @@
|
||||
renderEvents();
|
||||
});
|
||||
|
||||
window.addEventListener('ndkEose', (event) => {
|
||||
if (!allEventsFetchInFlight || !allEventsFetchSub?.subId) return;
|
||||
const eoseSubId = String(event?.detail?.subId || '');
|
||||
if (!eoseSubId || eoseSubId !== String(allEventsFetchSub.subId)) return;
|
||||
|
||||
const { kindsCount, totalEvents } = getCachedKindsAndEventTotals();
|
||||
finalizeGetAllEventsFetch(`Get all events complete · ${kindsCount} kinds · ${totalEvents.toLocaleString()} cached events`);
|
||||
});
|
||||
|
||||
window.addEventListener('ndkEvent', (event) => {
|
||||
const evt = event?.detail;
|
||||
if (!evt || !Number.isFinite(Number(evt.kind)) || !evt.id) return;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"VERSION": "v0.7.17",
|
||||
"VERSION_NUMBER": "0.7.17",
|
||||
"BUILD_DATE": "2026-06-09T19:15:08.620Z"
|
||||
"VERSION": "v0.7.18",
|
||||
"VERSION_NUMBER": "0.7.18",
|
||||
"BUILD_DATE": "2026-06-14T12:07:35.533Z"
|
||||
}
|
||||
|
||||
@@ -1179,6 +1179,7 @@ function startRelayHealthCheck() {
|
||||
class MessageBasedSigner {
|
||||
constructor() {
|
||||
this.pubkey = null;
|
||||
this.signedEventsBySig = new Map(); // sig -> signed raw event from signer page
|
||||
}
|
||||
|
||||
async user() {
|
||||
@@ -1196,12 +1197,59 @@ class MessageBasedSigner {
|
||||
|
||||
async sign(event) {
|
||||
console.log('[Worker] MessageBasedSigner: Signing event kind:', event.kind);
|
||||
|
||||
|
||||
// Request signing from page
|
||||
const signedEvent = await this.requestFromPage('signEvent', { event });
|
||||
|
||||
|
||||
const sig = String(signedEvent?.sig || '').trim();
|
||||
if (!sig) {
|
||||
throw new Error('signEvent returned no signature');
|
||||
}
|
||||
|
||||
// Keep a snapshot so caller can align NDKEvent fields to exactly what was signed.
|
||||
const snapshot = {
|
||||
id: String(signedEvent?.id || ''),
|
||||
pubkey: String(signedEvent?.pubkey || ''),
|
||||
created_at: Number(signedEvent?.created_at || 0),
|
||||
kind: Number(signedEvent?.kind),
|
||||
content: String(signedEvent?.content || ''),
|
||||
tags: Array.isArray(signedEvent?.tags)
|
||||
? signedEvent.tags.map((tag) => Array.isArray(tag) ? tag.map((v) => String(v ?? '')) : [String(tag ?? '')])
|
||||
: [],
|
||||
sig
|
||||
};
|
||||
|
||||
this.signedEventsBySig.set(sig, snapshot);
|
||||
if (this.signedEventsBySig.size > 200) {
|
||||
const oldestKey = this.signedEventsBySig.keys().next().value;
|
||||
if (oldestKey) this.signedEventsBySig.delete(oldestKey);
|
||||
}
|
||||
|
||||
console.log('[Worker] MessageBasedSigner: Event signed');
|
||||
return signedEvent.sig;
|
||||
return sig;
|
||||
}
|
||||
|
||||
applySignedSnapshotToEvent(ndkEvent) {
|
||||
if (!ndkEvent) return false;
|
||||
|
||||
const sig = String(ndkEvent?.sig || '').trim();
|
||||
if (!sig) return false;
|
||||
|
||||
const snapshot = this.signedEventsBySig.get(sig);
|
||||
if (!snapshot) return false;
|
||||
|
||||
this.signedEventsBySig.delete(sig);
|
||||
|
||||
if (snapshot.id) ndkEvent.id = snapshot.id;
|
||||
if (snapshot.pubkey) ndkEvent.pubkey = snapshot.pubkey;
|
||||
if (Number.isFinite(snapshot.created_at) && snapshot.created_at > 0) ndkEvent.created_at = snapshot.created_at;
|
||||
if (Number.isFinite(snapshot.kind)) ndkEvent.kind = snapshot.kind;
|
||||
ndkEvent.content = String(snapshot.content || '');
|
||||
ndkEvent.tags = Array.isArray(snapshot.tags)
|
||||
? snapshot.tags.map((tag) => Array.isArray(tag) ? tag.map((v) => String(v ?? '')) : [String(tag ?? '')])
|
||||
: [];
|
||||
ndkEvent.sig = snapshot.sig;
|
||||
return true;
|
||||
}
|
||||
|
||||
async encrypt(recipient, plaintext) {
|
||||
@@ -1307,6 +1355,16 @@ class MessageBasedSigner {
|
||||
// Create message-based signer instance
|
||||
let messageSigner = null;
|
||||
|
||||
async function signEventWithMessageSigner(event, opts) {
|
||||
if (!event) throw new Error('Missing event to sign');
|
||||
await event.sign(messageSigner, opts);
|
||||
try {
|
||||
messageSigner?.applySignedSnapshotToEvent?.(event);
|
||||
} catch (error) {
|
||||
console.warn('[Worker] Failed applying signed snapshot to event:', error?.message || error);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize NDK with Dexie cache and message-based signer
|
||||
async function initNDK() {
|
||||
console.log('[Worker] Initializing NDK...');
|
||||
@@ -2662,7 +2720,7 @@ async function publishDirectProofs(debugContext = null) {
|
||||
});
|
||||
|
||||
log('sign 7375 start', { mintUrl });
|
||||
await tokenEvent.sign(messageSigner);
|
||||
await signEventWithMessageSigner(tokenEvent);
|
||||
log('sign 7375 done', { mintUrl });
|
||||
|
||||
log('publish 7375 start', { mintUrl });
|
||||
@@ -2687,7 +2745,7 @@ async function publishDirectProofs(debugContext = null) {
|
||||
content: '',
|
||||
created_at: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
await deletionEvent.sign(messageSigner);
|
||||
await signEventWithMessageSigner(deletionEvent);
|
||||
await deletionEvent.publish();
|
||||
}
|
||||
log('delete old 7375 done');
|
||||
@@ -2726,7 +2784,7 @@ async function publishDirectProofs(debugContext = null) {
|
||||
});
|
||||
|
||||
log('sign 17375 start');
|
||||
await walletEvent.sign(messageSigner);
|
||||
await signEventWithMessageSigner(walletEvent);
|
||||
log('sign 17375 done');
|
||||
|
||||
log('publish 17375 start');
|
||||
@@ -2750,7 +2808,7 @@ async function publishDirectProofs(debugContext = null) {
|
||||
content: '',
|
||||
created_at: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
await deletionEvent.sign(messageSigner);
|
||||
await signEventWithMessageSigner(deletionEvent);
|
||||
await deletionEvent.publish();
|
||||
}
|
||||
log('delete old 17375 done');
|
||||
@@ -2951,7 +3009,7 @@ async function publishSpendingHistoryEvent(entry = {}) {
|
||||
created_at: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
|
||||
await historyEvent.sign(messageSigner);
|
||||
await signEventWithMessageSigner(historyEvent);
|
||||
const relaySet = await historyEvent.publish();
|
||||
if (relaySet && relaySet.size > 0) {
|
||||
for (const relay of relaySet) {
|
||||
@@ -3003,7 +3061,7 @@ async function handleWalletPublishMintList(requestId, relays, receiveMints, port
|
||||
mintListEvent.mints = mints;
|
||||
mintListEvent.relays = relayUrls;
|
||||
if (p2pk) mintListEvent.p2pk = p2pk;
|
||||
await mintListEvent.sign(messageSigner);
|
||||
await signEventWithMessageSigner(mintListEvent);
|
||||
const relaySet = await mintListEvent.publishReplaceable();
|
||||
eventId = mintListEvent.id || null;
|
||||
publishedRelayCount = relaySet ? relaySet.size : 0;
|
||||
@@ -3019,7 +3077,7 @@ async function handleWalletPublishMintList(requestId, relays, receiveMints, port
|
||||
content: '',
|
||||
created_at: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
await mintListEvent.sign(messageSigner);
|
||||
await signEventWithMessageSigner(mintListEvent);
|
||||
const relaySet = await mintListEvent.publish();
|
||||
eventId = mintListEvent.id || null;
|
||||
publishedRelayCount = relaySet ? relaySet.size : 0;
|
||||
@@ -3233,7 +3291,7 @@ async function handleWalletSendNutzap(
|
||||
created_at: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
|
||||
await nutzapEvent.sign(messageSigner);
|
||||
await signEventWithMessageSigner(nutzapEvent);
|
||||
|
||||
let relaySet = null;
|
||||
if (recipientRelayUrls.length > 0 && NDKRelaySet?.fromRelayUrls) {
|
||||
@@ -4256,7 +4314,7 @@ async function publishUserSettingsNow() {
|
||||
created_at: now
|
||||
});
|
||||
|
||||
await ndkEvent.sign(messageSigner);
|
||||
await signEventWithMessageSigner(ndkEvent);
|
||||
const relaySet = await ndkEvent.publish();
|
||||
if (relaySet && relaySet.size > 0) {
|
||||
for (const relay of relaySet) {
|
||||
@@ -5304,7 +5362,7 @@ async function handlePublish(requestId, event, port) {
|
||||
|
||||
// Sign using message-based signer (will request signing from page)
|
||||
console.log('[Worker] Requesting signature from page...');
|
||||
await ndkEvent.sign(messageSigner);
|
||||
await signEventWithMessageSigner(ndkEvent);
|
||||
console.log('[Worker] Event signed, publishing to relays...');
|
||||
|
||||
// Publish to relays
|
||||
|
||||
Reference in New Issue
Block a user