From 18c34b63de8f102caa35985396f1763cc351b754 Mon Sep 17 00:00:00 2001 From: Scrum4Me Agent <30029041+madhura68@users.noreply.github.com> Date: Thu, 7 May 2026 21:34:41 +0200 Subject: [PATCH] =?UTF-8?q?PBI-55:=20src/lib/push-trigger.ts=20=E2=80=93?= =?UTF-8?q?=20fire-and-forget=20push=20helper=20with=205s=20AbortControlle?= =?UTF-8?q?r=20timeout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .env.example | 4 ++++ src/lib/push-trigger.ts | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/lib/push-trigger.ts diff --git a/.env.example b/.env.example index 6a3e89c..4a99af7 100644 --- a/.env.example +++ b/.env.example @@ -3,3 +3,7 @@ DATABASE_URL="postgresql://user:pass@host:5432/dbname" # API token from Scrum4Me → /settings/tokens SCRUM4ME_TOKEN="" + +# Internal push endpoint (main-app) for web-push notifications +INTERNAL_PUSH_URL="" +INTERNAL_PUSH_SECRET="" diff --git a/src/lib/push-trigger.ts b/src/lib/push-trigger.ts new file mode 100644 index 0000000..fb0434a --- /dev/null +++ b/src/lib/push-trigger.ts @@ -0,0 +1,22 @@ +export type PushPayload = { title: string; body: string; url: string; tag?: string }; + +export async function triggerPush(userId: string, payload: PushPayload): Promise { + const url = process.env.INTERNAL_PUSH_URL; + const secret = process.env.INTERNAL_PUSH_SECRET; + if (!url || !secret) return; // feature-gated + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), 5000); + try { + const res = await fetch(url, { + method: 'POST', + headers: { 'content-type': 'application/json', authorization: `Bearer ${secret}` }, + body: JSON.stringify({ userId, payload }), + signal: controller.signal, + }); + if (!res.ok) console.warn('[push-trigger] non-2xx', res.status); + } catch (err) { + console.error('[push-trigger]', err); + } finally { + clearTimeout(timeout); + } +}