From 85c964be3d227a5d43e1374a831db114f7c715e0 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Fri, 5 Dec 2025 13:21:20 -0300 Subject: [PATCH] enableReconnect() always update the filters to the time of the last received event on each subscription. --- abstract-pool.ts | 4 +-- abstract-relay.ts | 14 ++++++++--- jsr.json | 2 +- package.json | 2 +- pool.test.ts | 7 ++---- relay.test.ts | 63 ----------------------------------------------- 6 files changed, 16 insertions(+), 76 deletions(-) diff --git a/abstract-pool.ts b/abstract-pool.ts index 74bc8a8..468409b 100644 --- a/abstract-pool.ts +++ b/abstract-pool.ts @@ -36,7 +36,7 @@ export class AbstractSimplePool { public verifyEvent: Nostr['verifyEvent'] public enablePing: boolean | undefined - public enableReconnect: boolean | ((filters: Filter[]) => Filter[]) | undefined + public enableReconnect: boolean public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise) public trustedRelayURLs: Set = new Set() @@ -46,7 +46,7 @@ export class AbstractSimplePool { this.verifyEvent = opts.verifyEvent this._WebSocket = opts.websocketImplementation this.enablePing = opts.enablePing - this.enableReconnect = opts.enableReconnect + this.enableReconnect = opts.enableReconnect || false this.automaticallyAuth = opts.automaticallyAuth } diff --git a/abstract-relay.ts b/abstract-relay.ts index 23eef04..56a1939 100644 --- a/abstract-relay.ts +++ b/abstract-relay.ts @@ -16,7 +16,7 @@ export type AbstractRelayConstructorOptions = { verifyEvent: Nostr['verifyEvent'] websocketImplementation?: typeof WebSocket enablePing?: boolean - enableReconnect?: boolean | ((filters: Filter[]) => Filter[]) + enableReconnect?: boolean } export class SendingOnClosedConnection extends Error { @@ -42,7 +42,7 @@ export class AbstractRelay { public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000] public openSubs: Map = new Map() public enablePing: boolean | undefined - public enableReconnect: boolean | ((filters: Filter[]) => Filter[]) + public enableReconnect: boolean private connectionTimeoutHandle: ReturnType | undefined private reconnectTimeoutHandle: ReturnType | undefined private pingTimeoutHandle: ReturnType | undefined @@ -166,8 +166,12 @@ export class AbstractRelay { // resubscribe to all open subscriptions for (const sub of this.openSubs.values()) { sub.eosed = false - if (isReconnection && typeof this.enableReconnect === 'function') { - sub.filters = this.enableReconnect(sub.filters) + if (isReconnection) { + for (let f = 0; f < sub.filters.length; f++) { + if (sub.lastEmitted) { + sub.filters[f].since = sub.lastEmitted + 1 + } + } } sub.fire() } @@ -299,6 +303,7 @@ export class AbstractRelay { if (this.verifyEvent(event) && matchFilters(so.filters, event)) { so.onevent(event) } + if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at return } case 'COUNT': { @@ -469,6 +474,7 @@ export class Subscription { public readonly relay: AbstractRelay public readonly id: string + public lastEmitted: number | undefined public closed: boolean = false public eosed: boolean = false public filters: Filter[] diff --git a/jsr.json b/jsr.json index 48f5050..6615697 100644 --- a/jsr.json +++ b/jsr.json @@ -1,6 +1,6 @@ { "name": "@nostr/tools", - "version": "2.19.0", + "version": "2.19.1", "exports": { ".": "./index.ts", "./core": "./core.ts", diff --git a/package.json b/package.json index ddc1bbe..e79107d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "nostr-tools", - "version": "2.19.0", + "version": "2.19.1", "description": "Tools for making a Nostr client.", "repository": { "type": "git", diff --git a/pool.test.ts b/pool.test.ts index 4942182..f385c16 100644 --- a/pool.test.ts +++ b/pool.test.ts @@ -306,12 +306,9 @@ test('reconnect on disconnect in pool', async () => { test('reconnect with filter update in pool', async () => { const mockRelay = mockRelays[0] - const newSince = Math.floor(Date.now() / 1000) pool = new SimplePool({ enablePing: true, - enableReconnect: filters => { - return filters.map(f => ({ ...f, since: newSince })) - }, + enableReconnect: true, }) const relay = await pool.ensureRelay(mockRelay.url) relay.pingTimeout = 50 @@ -364,7 +361,7 @@ test('reconnect with filter update in pool', async () => { expect(closes).toBe(1) // check if filter was updated - expect(sub.filters[0].since).toBe(newSince) + expect(sub.filters[0].since).toBeGreaterThan(1) }) test('track relays when publishing', async () => { diff --git a/relay.test.ts b/relay.test.ts index a6342b5..c08c0b0 100644 --- a/relay.test.ts +++ b/relay.test.ts @@ -336,66 +336,3 @@ test('reconnect on disconnect', async () => { expect(relay.connected).toBeTrue() expect(closes).toBe(1) // should not have closed again }) - -test('reconnect with filter update', async () => { - const mockRelay = new MockRelay() - const newSince = Math.floor(Date.now() / 1000) - const relay = new Relay(mockRelay.url, { - enablePing: true, - enableReconnect: filters => { - return filters.map(f => ({ ...f, since: newSince })) - }, - }) - relay.pingTimeout = 50 - relay.pingFrequency = 50 - relay.resubscribeBackoff = [50, 100] - - let closes = 0 - relay.onclose = () => { - closes++ - } - - await relay.connect() - expect(relay.connected).toBeTrue() - - const sub = relay.subscribe([{ kinds: [1], since: 0 }], { onevent: () => {} }) - expect(sub.filters[0].since).toBe(0) - - // wait for the first ping to succeed - await new Promise(resolve => setTimeout(resolve, 75)) - expect(closes).toBe(0) - - // now make it unresponsive - mockRelay.unresponsive = true - - // wait for the second ping to fail, which will trigger a close - await new Promise(resolve => { - const interval = setInterval(() => { - if (closes > 0) { - clearInterval(interval) - resolve(null) - } - }, 10) - }) - expect(closes).toBe(1) - expect(relay.connected).toBeFalse() - - // now make it responsive again - mockRelay.unresponsive = false - - // wait for reconnect - await new Promise(resolve => { - const interval = setInterval(() => { - if (relay.connected) { - clearInterval(interval) - resolve(null) - } - }, 10) - }) - - expect(relay.connected).toBeTrue() - expect(closes).toBe(1) - - // check if filter was updated - expect(sub.filters[0].since).toBe(newSince) -})