chore: migrate to v3, Doppler secrets, clean up legacy code
Some checks failed
CI / v3 / Check ui (pull_request) Failing after 15s
CI / v3 / Test backend (pull_request) Failing after 16s
CI / v3 / Docker / backend (pull_request) Has been skipped
CI / v3 / Docker / runner (pull_request) Has been skipped
CI / v3 / Docker / ui (pull_request) Has been skipped
Some checks failed
CI / v3 / Check ui (pull_request) Failing after 15s
CI / v3 / Test backend (pull_request) Failing after 16s
CI / v3 / Docker / backend (pull_request) Has been skipped
CI / v3 / Docker / runner (pull_request) Has been skipped
CI / v3 / Docker / ui (pull_request) Has been skipped
- Remove all pre-v3 code: scraper, ui-v2, backend v1, ios v1+v2, legacy CI workflows - Flatten v3/ contents to repo root - Add Doppler secrets management (project=libnovel, config=prd) - Add justfile with doppler run wrappers for all docker compose commands - Strip hardcoded env fallbacks from docker-compose.yml - Add minimal README.md - Clean up .gitignore
This commit is contained in:
@@ -1,8 +1,47 @@
|
||||
import type { Handle } from '@sveltejs/kit';
|
||||
import { handleErrorWithSentry } from '@sentry/sveltekit';
|
||||
import * as Sentry from '@sentry/sveltekit';
|
||||
import { randomBytes, createHmac } from 'node:crypto';
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { env as pubEnv } from '$env/dynamic/public';
|
||||
import { log } from '$lib/server/logger';
|
||||
import { createUserSession, touchUserSession, isSessionRevoked } from '$lib/server/pocketbase';
|
||||
import { drain as drainPresignCache } from '$lib/server/presignCache';
|
||||
|
||||
// ─── Sentry / GlitchTip server-side error tracking ────────────────────────────
|
||||
// No-op when PUBLIC_GLITCHTIP_DSN is unset (e.g. local dev).
|
||||
if (pubEnv.PUBLIC_GLITCHTIP_DSN) {
|
||||
Sentry.init({
|
||||
dsn: pubEnv.PUBLIC_GLITCHTIP_DSN,
|
||||
tracesSampleRate: 0.1
|
||||
});
|
||||
}
|
||||
|
||||
export const handleError = handleErrorWithSentry();
|
||||
|
||||
// ─── Graceful shutdown ────────────────────────────────────────────────────────
|
||||
//
|
||||
// When Docker/Kubernetes sends SIGTERM (or the user sends SIGINT), we:
|
||||
// 1. Set shuttingDown = true so new requests immediately receive 503.
|
||||
// 2. Flush/drain in-process caches (presign URL cache).
|
||||
// 3. Allow Node.js to exit naturally once in-flight requests finish.
|
||||
//
|
||||
// adapter-node does not provide a built-in hook for this, so we wire it here
|
||||
// in hooks.server.ts which runs in the server Node.js process.
|
||||
|
||||
let shuttingDown = false;
|
||||
|
||||
function shutdown(signal: string) {
|
||||
if (shuttingDown) return;
|
||||
shuttingDown = true;
|
||||
log.info('shutdown', `received ${signal}, draining in-flight requests`);
|
||||
drainPresignCache();
|
||||
// Don't call process.exit() — let Node exit naturally once the event loop
|
||||
// is empty (adapter-node closes the HTTP server on its own).
|
||||
}
|
||||
|
||||
process.once('SIGTERM', () => shutdown('SIGTERM'));
|
||||
process.once('SIGINT', () => shutdown('SIGINT'));
|
||||
|
||||
const SESSION_COOKIE = 'libnovel_session';
|
||||
const AUTH_COOKIE = 'libnovel_auth';
|
||||
@@ -70,6 +109,12 @@ export function parseAuthToken(token: string): { id: string; username: string; r
|
||||
// ─── Hook ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
export const handle: Handle = async ({ event, resolve }) => {
|
||||
// During graceful shutdown, reject new requests immediately so the load
|
||||
// balancer / Docker health-check can drain existing connections.
|
||||
if (shuttingDown) {
|
||||
return new Response('Service shutting down', { status: 503 });
|
||||
}
|
||||
|
||||
// Anonymous session cookie (for reading progress)
|
||||
let sessionId = event.cookies.get(SESSION_COOKIE) ?? '';
|
||||
if (!sessionId) {
|
||||
|
||||
Reference in New Issue
Block a user