From 0d284e620f91fc4bf780ac0fc449a12696db122f Mon Sep 17 00:00:00 2001 From: Rishi Ranjan <101rishidsr@gmail.com> Date: Sat, 14 Feb 2026 18:50:08 +0530 Subject: [PATCH 01/10] Added failed relay publish table + indexes to schema and Added table creation + migration support in DB --- db/schema.sql | 14 ++++++++- pages/api/db/clear-failed-publish.ts | 10 ++++++ pages/api/db/get-failed-publishes.ts | 45 ++++++++++++++++++++------- pages/api/db/track-failed-publish.ts | 20 +++++++++--- utils/db/db-client.ts | 5 +-- utils/db/db-service.ts | 19 +++++++++++ utils/nostr/nostr-helper-functions.ts | 11 ++++--- 7 files changed, 101 insertions(+), 23 deletions(-) diff --git a/db/schema.sql b/db/schema.sql index 6d3c9b2d..71997add 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -123,4 +123,16 @@ CREATE TABLE IF NOT EXISTS discount_codes ( ); CREATE INDEX IF NOT EXISTS idx_discount_codes_pubkey ON discount_codes(pubkey); -CREATE INDEX IF NOT EXISTS idx_discount_codes_code ON discount_codes(code); \ No newline at end of file +CREATE INDEX IF NOT EXISTS idx_discount_codes_code ON discount_codes(code); + +-- Failed relay publish tracking table +CREATE TABLE IF NOT EXISTS failed_relay_publishes ( + event_id TEXT PRIMARY KEY, + relays TEXT NOT NULL, + event_data TEXT, + created_at BIGINT NOT NULL, + retry_count INTEGER DEFAULT 0 +); + +CREATE INDEX IF NOT EXISTS idx_failed_relay_publishes_created_at ON failed_relay_publishes(created_at ASC); +CREATE INDEX IF NOT EXISTS idx_failed_relay_publishes_retry_count ON failed_relay_publishes(retry_count); \ No newline at end of file diff --git a/pages/api/db/clear-failed-publish.ts b/pages/api/db/clear-failed-publish.ts index d10f096a..e1d23890 100644 --- a/pages/api/db/clear-failed-publish.ts +++ b/pages/api/db/clear-failed-publish.ts @@ -21,6 +21,16 @@ export default async function handler( client = await dbPool.connect(); + await client.query(` + CREATE TABLE IF NOT EXISTS failed_relay_publishes ( + event_id TEXT PRIMARY KEY, + relays TEXT NOT NULL, + event_data TEXT, + created_at BIGINT NOT NULL, + retry_count INTEGER DEFAULT 0 + ) + `); + if (incrementRetry) { // Increment retry count await client.query( diff --git a/pages/api/db/get-failed-publishes.ts b/pages/api/db/get-failed-publishes.ts index 55650cfd..801ae5d3 100644 --- a/pages/api/db/get-failed-publishes.ts +++ b/pages/api/db/get-failed-publishes.ts @@ -15,24 +15,45 @@ export default async function handler( try { client = await dbPool.connect(); + await client.query(` + CREATE TABLE IF NOT EXISTS failed_relay_publishes ( + event_id TEXT PRIMARY KEY, + relays TEXT NOT NULL, + event_data TEXT, + created_at BIGINT NOT NULL, + retry_count INTEGER DEFAULT 0 + ) + `); + + await client.query(` + ALTER TABLE failed_relay_publishes + ADD COLUMN IF NOT EXISTS event_data TEXT + `); + // Get all failed publishes with retry count < 5 (limit retries) const result = await client.query( - `SELECT fp.event_id, fp.relays, fp.retry_count, e.event_data - FROM failed_relay_publishes fp - LEFT JOIN events e ON fp.event_id = e.id - WHERE fp.retry_count < 5 - ORDER BY fp.created_at ASC + `SELECT event_id, relays, retry_count, event_data + FROM failed_relay_publishes + WHERE retry_count < 5 + AND event_data IS NOT NULL + ORDER BY created_at ASC LIMIT 50` ); const failedPublishes = result.rows - .filter((row: any) => row.event_data) - .map((row: any) => ({ - eventId: row.event_id, - relays: JSON.parse(row.relays), - event: JSON.parse(row.event_data), - retryCount: row.retry_count, - })); + .map((row: any) => { + try { + return { + eventId: row.event_id, + relays: JSON.parse(row.relays), + event: JSON.parse(row.event_data), + retryCount: row.retry_count, + }; + } catch { + return null; + } + }) + .filter(Boolean); return res.status(200).json(failedPublishes); } catch (error) { diff --git a/pages/api/db/track-failed-publish.ts b/pages/api/db/track-failed-publish.ts index 05c7b5e7..431f040a 100644 --- a/pages/api/db/track-failed-publish.ts +++ b/pages/api/db/track-failed-publish.ts @@ -13,7 +13,7 @@ export default async function handler( let client; try { - const { eventId, relays } = req.body; + const { eventId, relays, event } = req.body; if (!eventId || !relays || !Array.isArray(relays)) { return res.status(400).json({ error: "Invalid request body" }); @@ -26,19 +26,31 @@ export default async function handler( CREATE TABLE IF NOT EXISTS failed_relay_publishes ( event_id TEXT PRIMARY KEY, relays TEXT NOT NULL, + event_data TEXT, created_at BIGINT NOT NULL, retry_count INTEGER DEFAULT 0 ) `); + await client.query(` + ALTER TABLE failed_relay_publishes + ADD COLUMN IF NOT EXISTS event_data TEXT + `); + // Insert or update the failed publish record await client.query( - `INSERT INTO failed_relay_publishes (event_id, relays, created_at, retry_count) - VALUES ($1, $2, $3, 0) + `INSERT INTO failed_relay_publishes (event_id, relays, event_data, created_at, retry_count) + VALUES ($1, $2, $3, $4, 0) ON CONFLICT (event_id) DO UPDATE SET relays = EXCLUDED.relays, + event_data = EXCLUDED.event_data, created_at = EXCLUDED.created_at`, - [eventId, JSON.stringify(relays), Math.floor(Date.now() / 1000)] + [ + eventId, + JSON.stringify(relays), + event ? JSON.stringify(event) : null, + Math.floor(Date.now() / 1000), + ] ); return res.status(200).json({ success: true }); diff --git a/utils/db/db-client.ts b/utils/db/db-client.ts index 11f61679..402ca260 100644 --- a/utils/db/db-client.ts +++ b/utils/db/db-client.ts @@ -52,13 +52,14 @@ export async function deleteEventsFromDatabase( export async function trackFailedRelayPublish( eventId: string, - relays: string[] + relays: string[], + event?: NostrEvent ): Promise { try { await fetch("/api/db/track-failed-publish", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ eventId, relays }), + body: JSON.stringify({ eventId, relays, event }), }); } catch (error) { console.error("Failed to track failed relay publish:", error); diff --git a/utils/db/db-service.ts b/utils/db/db-service.ts index f6a485ae..d95032c6 100644 --- a/utils/db/db-service.ts +++ b/utils/db/db-service.ts @@ -182,6 +182,18 @@ async function initializeTables(): Promise { CREATE INDEX IF NOT EXISTS idx_discount_codes_pubkey ON discount_codes(pubkey); CREATE INDEX IF NOT EXISTS idx_discount_codes_code ON discount_codes(code); + + -- Failed relay publish tracking table + CREATE TABLE IF NOT EXISTS failed_relay_publishes ( + event_id TEXT PRIMARY KEY, + relays TEXT NOT NULL, + event_data TEXT, + created_at BIGINT NOT NULL, + retry_count INTEGER DEFAULT 0 + ); + + CREATE INDEX IF NOT EXISTS idx_failed_relay_publishes_created_at ON failed_relay_publishes(created_at ASC); + CREATE INDEX IF NOT EXISTS idx_failed_relay_publishes_retry_count ON failed_relay_publishes(retry_count); `); // Migration: Add is_read, order_status, order_id columns to existing message_events tables @@ -210,6 +222,13 @@ async function initializeTables(): Promise { ALTER TABLE message_events ADD COLUMN order_id TEXT DEFAULT NULL; CREATE INDEX IF NOT EXISTS idx_message_events_order_id ON message_events(order_id); END IF; + + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'failed_relay_publishes' AND column_name = 'event_data' + ) THEN + ALTER TABLE failed_relay_publishes ADD COLUMN event_data TEXT; + END IF; END $$; `); diff --git a/utils/nostr/nostr-helper-functions.ts b/utils/nostr/nostr-helper-functions.ts index 994724b9..569e595d 100644 --- a/utils/nostr/nostr-helper-functions.ts +++ b/utils/nostr/nostr-helper-functions.ts @@ -475,7 +475,8 @@ export async function sendGiftWrappedMessageEvent( const { trackFailedRelayPublish } = await import("@/utils/db/db-client"); await trackFailedRelayPublish( giftWrappedMessageEvent.id, - allWriteRelays + allWriteRelays, + giftWrappedMessageEvent ).catch(console.error); } } @@ -1006,9 +1007,11 @@ export async function finalizeAndSendNostrEvent( error ); const { trackFailedRelayPublish } = await import("@/utils/db/db-client"); - await trackFailedRelayPublish(signedEvent.id, allWriteRelays).catch( - console.error - ); + await trackFailedRelayPublish( + signedEvent.id, + allWriteRelays, + signedEvent + ).catch(console.error); } // return the signed event to caller so we know generated IDs From 6bfce069fe16e136c1cf3505261875ce492fb3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?calvadev=E2=9A=A1=EF=B8=8F?= <32919103+calvadev@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:49:12 -0700 Subject: [PATCH 02/10] Update utils/db/db-service.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- utils/db/db-service.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/utils/db/db-service.ts b/utils/db/db-service.ts index d95032c6..61299d34 100644 --- a/utils/db/db-service.ts +++ b/utils/db/db-service.ts @@ -222,13 +222,6 @@ async function initializeTables(): Promise { ALTER TABLE message_events ADD COLUMN order_id TEXT DEFAULT NULL; CREATE INDEX IF NOT EXISTS idx_message_events_order_id ON message_events(order_id); END IF; - - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = 'failed_relay_publishes' AND column_name = 'event_data' - ) THEN - ALTER TABLE failed_relay_publishes ADD COLUMN event_data TEXT; - END IF; END $$; `); From 884415e7de702a532d1769e4a7d3906d97f34cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?calvadev=E2=9A=A1=EF=B8=8F?= <32919103+calvadev@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:49:21 -0700 Subject: [PATCH 03/10] Update pages/api/db/track-failed-publish.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- pages/api/db/track-failed-publish.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pages/api/db/track-failed-publish.ts b/pages/api/db/track-failed-publish.ts index 431f040a..99be15ac 100644 --- a/pages/api/db/track-failed-publish.ts +++ b/pages/api/db/track-failed-publish.ts @@ -32,11 +32,6 @@ export default async function handler( ) `); - await client.query(` - ALTER TABLE failed_relay_publishes - ADD COLUMN IF NOT EXISTS event_data TEXT - `); - // Insert or update the failed publish record await client.query( `INSERT INTO failed_relay_publishes (event_id, relays, event_data, created_at, retry_count) From 5f419c11858c4b8e4deeac8a62e0eee421f710da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?calvadev=E2=9A=A1=EF=B8=8F?= <32919103+calvadev@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:49:27 -0700 Subject: [PATCH 04/10] Update pages/api/db/get-failed-publishes.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- pages/api/db/get-failed-publishes.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pages/api/db/get-failed-publishes.ts b/pages/api/db/get-failed-publishes.ts index 801ae5d3..8d152a2d 100644 --- a/pages/api/db/get-failed-publishes.ts +++ b/pages/api/db/get-failed-publishes.ts @@ -25,11 +25,6 @@ export default async function handler( ) `); - await client.query(` - ALTER TABLE failed_relay_publishes - ADD COLUMN IF NOT EXISTS event_data TEXT - `); - // Get all failed publishes with retry count < 5 (limit retries) const result = await client.query( `SELECT event_id, relays, retry_count, event_data From a7376f451c25cab953aacb98d102c3b5b49996f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?calvadev=E2=9A=A1=EF=B8=8F?= <32919103+calvadev@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:57:01 -0700 Subject: [PATCH 05/10] Remove table creation from get-failed-publishes API Removed the creation of the failed_relay_publishes table from the get-failed-publishes API. --- pages/api/db/get-failed-publishes.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pages/api/db/get-failed-publishes.ts b/pages/api/db/get-failed-publishes.ts index 1899917a..9bb0505e 100644 --- a/pages/api/db/get-failed-publishes.ts +++ b/pages/api/db/get-failed-publishes.ts @@ -19,16 +19,6 @@ export default async function handler( client = await dbPool.connect(); await ensureFailedRelayPublishesTable(client); - await client.query(` - CREATE TABLE IF NOT EXISTS failed_relay_publishes ( - event_id TEXT PRIMARY KEY, - relays TEXT NOT NULL, - event_data TEXT, - created_at BIGINT NOT NULL, - retry_count INTEGER DEFAULT 0 - ) - `); - // Get all failed publishes with retry count < 5 (limit retries) const result = await client.query( `SELECT event_id, event_data, relays, retry_count From c9fb6bcaf022751709a4e8bddad3e8623874e9d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?calvadev=E2=9A=A1=EF=B8=8F?= <32919103+calvadev@users.noreply.github.com> Date: Wed, 11 Mar 2026 15:57:33 -0700 Subject: [PATCH 06/10] Remove table creation from clear-failed-publish API Removed the creation of the 'failed_relay_publishes' table from the clear-failed-publish API. --- pages/api/db/clear-failed-publish.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pages/api/db/clear-failed-publish.ts b/pages/api/db/clear-failed-publish.ts index 7a7f2806..574282dd 100644 --- a/pages/api/db/clear-failed-publish.ts +++ b/pages/api/db/clear-failed-publish.ts @@ -25,16 +25,6 @@ export default async function handler( client = await dbPool.connect(); await ensureFailedRelayPublishesTable(client); - await client.query(` - CREATE TABLE IF NOT EXISTS failed_relay_publishes ( - event_id TEXT PRIMARY KEY, - relays TEXT NOT NULL, - event_data TEXT, - created_at BIGINT NOT NULL, - retry_count INTEGER DEFAULT 0 - ) - `); - if (incrementRetry) { // Increment retry count await client.query( From 1cef14264fea5ec947960eee0de56923f9b9d32a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?calvadev=E2=9A=A1=EF=B8=8F?= <32919103+calvadev@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:03:48 -0700 Subject: [PATCH 07/10] Update track-failed-publish.ts --- pages/api/db/track-failed-publish.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/db/track-failed-publish.ts b/pages/api/db/track-failed-publish.ts index 9676bea4..1619635a 100644 --- a/pages/api/db/track-failed-publish.ts +++ b/pages/api/db/track-failed-publish.ts @@ -32,7 +32,6 @@ export default async function handler( ON CONFLICT (event_id) DO UPDATE SET event_data = EXCLUDED.event_data, relays = EXCLUDED.relays, - event_data = EXCLUDED.event_data, created_at = EXCLUDED.created_at`, [ eventId, From 112efb102f690f93a86ea68f36c569b35d59825a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?calvadev=E2=9A=A1=EF=B8=8F?= <32919103+calvadev@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:11:57 -0700 Subject: [PATCH 08/10] Improve error handling for JSON parsing --- pages/api/db/get-failed-publishes.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pages/api/db/get-failed-publishes.ts b/pages/api/db/get-failed-publishes.ts index 9bb0505e..49372a43 100644 --- a/pages/api/db/get-failed-publishes.ts +++ b/pages/api/db/get-failed-publishes.ts @@ -30,6 +30,7 @@ export default async function handler( ); const failedPublishes = result.rows + .filter((row: any) => row.event_data) .map((row: any) => { try { return { @@ -38,7 +39,8 @@ export default async function handler( event: JSON.parse(row.event_data), retryCount: row.retry_count, }; - } catch { + } catch (e) { + console.error('Failed to parse row:', row.event_id, e); return null; } }) From b750439f81e632d3b877b6495b7346ac536a2f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?calvadev=E2=9A=A1=EF=B8=8F?= <32919103+calvadev@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:19:20 -0700 Subject: [PATCH 09/10] Remove failed relay publishes table creation Removed creation of failed_relay_publishes table and its indexes. --- utils/db/db-service.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/utils/db/db-service.ts b/utils/db/db-service.ts index ccd2e466..17f1d8cf 100644 --- a/utils/db/db-service.ts +++ b/utils/db/db-service.ts @@ -202,18 +202,6 @@ async function initializeTables(): Promise { CREATE INDEX IF NOT EXISTS idx_discount_codes_pubkey ON discount_codes(pubkey); CREATE INDEX IF NOT EXISTS idx_discount_codes_code ON discount_codes(code); - - -- Failed relay publish tracking table - CREATE TABLE IF NOT EXISTS failed_relay_publishes ( - event_id TEXT PRIMARY KEY, - relays TEXT NOT NULL, - event_data TEXT, - created_at BIGINT NOT NULL, - retry_count INTEGER DEFAULT 0 - ); - - CREATE INDEX IF NOT EXISTS idx_failed_relay_publishes_created_at ON failed_relay_publishes(created_at ASC); - CREATE INDEX IF NOT EXISTS idx_failed_relay_publishes_retry_count ON failed_relay_publishes(retry_count); `); // Migration: Add is_read, order_status, order_id columns to existing message_events tables From 864e97c2dae78a0b90c8c37b081e93d1caa6f637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?calvadev=E2=9A=A1=EF=B8=8F?= <32919103+calvadev@users.noreply.github.com> Date: Wed, 11 Mar 2026 16:20:48 -0700 Subject: [PATCH 10/10] Fix column definition in failed_relay_publishes table --- db/schema.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/schema.sql b/db/schema.sql index 1ecb25ff..ce3de500 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -128,8 +128,8 @@ CREATE INDEX IF NOT EXISTS idx_discount_codes_code ON discount_codes(code); -- Failed relay publish tracking table CREATE TABLE IF NOT EXISTS failed_relay_publishes ( event_id TEXT PRIMARY KEY, - relays TEXT NOT NULL, event_data TEXT, + relays TEXT NOT NULL, created_at BIGINT NOT NULL, retry_count INTEGER DEFAULT 0 );