diff --git a/AGENTS.md b/AGENTS.md index 80ffff5..ab04c64 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -28,7 +28,7 @@ npm run start npm run notifications:worker ``` -Repozytorium nie ma obecnie skryptu testów, osobnego skryptu type-check ani formattera. `npm run build` uruchamia kontrolę TypeScript wykonywaną przez Next.js. `npm run notifications:worker` uruchamia osobny proces Node do cyklicznego wywoływania endpointów Web Push na self-hostingu; wymaga równolegle działającego `npm run start` albo poprawnego `WTR_APP_URL`. Nie opisuj ani nie uruchamiaj nieistniejących komend jako standardowego workflow. +Repozytorium nie ma obecnie skryptu testów, osobnego skryptu type-check ani formattera. `npm run build` uruchamia kontrolę TypeScript wykonywaną przez Next.js. `npm run notifications:worker` uruchamia osobny proces Node do cyklicznego wywoływania endpointów Web Push na self-hostingu; wczytuje `.env` i `.env.local`, ale nadal wymaga równolegle działającego `npm run start` albo poprawnego `WTR_APP_URL`. Nie opisuj ani nie uruchamiaj nieistniejących komend jako standardowego workflow. ## Konwencje kodu diff --git a/README.md b/README.md index e588733..17cd79a 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ npm run start npm run notifications:worker ``` -Worker musi mieć dostęp do działającej aplikacji Next.js. Domyślnie odpytuje `http://127.0.0.1:3000`; jeśli aplikacja działa pod innym adresem albo portem, ustaw `WTR_APP_URL`. +Worker musi mieć dostęp do działającej aplikacji Next.js. Domyślnie odpytuje `http://127.0.0.1:3000`; jeśli aplikacja działa pod innym adresem albo portem, ustaw `WTR_APP_URL`. Skrypt workera sam wczytuje `.env` i `.env.local`, a zmienne podane bezpośrednio w shellu mają pierwszeństwo. ## Źródła danych @@ -154,7 +154,7 @@ NOTIFICATIONS_WARNING_INTERVAL_MINUTES=5 NOTIFICATIONS_MORNING_BRIEF_TIME=07:00 ``` -Klucze VAPID można wygenerować poleceniem `npx web-push generate-vapid-keys`. Worker `npm run notifications:worker` domyślnie odpytuje `http://127.0.0.1:3000`, więc `npm run start` musi działać równolegle na tym samym hoście albo `WTR_APP_URL` musi wskazywać właściwy adres aplikacji. Worker sprawdza ostrzeżenia co 5 minut i wysyła poranny brief po 07:00 czasu polskiego. Jeśli używasz zewnętrznego crona zamiast workera, cron ostrzeżeń powinien wywoływać `GET /api/notifications/check` z nagłówkiem `Authorization: Bearer ` albo `x-cron-secret`. Drugi cron, ustawiony na około 07:00 czasu polskiego, powinien wywoływać `GET /api/notifications/daily-brief` z tym samym nagłówkiem. +Klucze VAPID można wygenerować poleceniem `npx web-push generate-vapid-keys`. Worker `npm run notifications:worker` wczytuje `.env` i `.env.local`, domyślnie odpytuje `http://127.0.0.1:3000`, więc `npm run start` musi działać równolegle na tym samym hoście albo `WTR_APP_URL` musi wskazywać właściwy adres aplikacji. Worker sprawdza ostrzeżenia co 5 minut i wysyła poranny brief po 07:00 czasu polskiego. Jeśli używasz zewnętrznego crona zamiast workera, cron ostrzeżeń powinien wywoływać `GET /api/notifications/check` z nagłówkiem `Authorization: Bearer ` albo `x-cron-secret`. Drugi cron, ustawiony na około 07:00 czasu polskiego, powinien wywoływać `GET /api/notifications/daily-brief` z tym samym nagłówkiem. ## Wdrożenie na Vercel diff --git a/scripts/notification-worker.mjs b/scripts/notification-worker.mjs index 959fb30..f8f6459 100644 --- a/scripts/notification-worker.mjs +++ b/scripts/notification-worker.mjs @@ -1,8 +1,14 @@ +import { existsSync, readFileSync } from "node:fs"; + const DEFAULT_APP_URL = "http://127.0.0.1:3000"; const DEFAULT_WARNING_INTERVAL_MINUTES = 5; const DEFAULT_MORNING_BRIEF_TIME = "07:00"; const LOOP_INTERVAL_MS = 30_000; +const initialEnvKeys = new Set(Object.keys(process.env)); +loadEnvFile(".env", false); +loadEnvFile(".env.local", true); + const appUrl = normalizeAppUrl(process.env.WTR_APP_URL ?? process.env.NEXT_PUBLIC_APP_URL ?? DEFAULT_APP_URL); const cronSecret = process.env.NOTIFICATIONS_CRON_SECRET ?? ""; const warningIntervalMinutes = readPositiveNumber(process.env.NOTIFICATIONS_WARNING_INTERVAL_MINUTES, DEFAULT_WARNING_INTERVAL_MINUTES); @@ -12,6 +18,22 @@ let lastWarningCheckAt = 0; let lastMorningBriefDate = ""; let isRunningTick = false; +function loadEnvFile(path, overrideLoadedValues) { + if (!existsSync(path)) return; + const lines = readFileSync(path, "utf8").split(/\r?\n/); + for (const line of lines) { + const trimmedLine = line.trim(); + if (!trimmedLine || trimmedLine.startsWith("#")) continue; + const separatorIndex = trimmedLine.indexOf("="); + if (separatorIndex === -1) continue; + const key = trimmedLine.slice(0, separatorIndex).trim(); + const rawValue = trimmedLine.slice(separatorIndex + 1).trim(); + if (!key || initialEnvKeys.has(key)) continue; + if (!overrideLoadedValues && process.env[key] !== undefined) continue; + process.env[key] = rawValue.replace(/^['"]|['"]$/g, ""); + } +} + function normalizeAppUrl(value) { return value.replace(/\/+$/, ""); }