Fix silent login failure on infra without HTTPS yet, and build-time SQLITE_BUSY
Session cookie always set Secure (tied to NODE_ENV=production, hardcoded in the Dockerfile), which the browser silently drops over plain HTTP — looked like login accepted the password but bounced straight back to /login. Secure now only drops when COOKIE_ALLOW_INSECURE=true, for temporary use before the HTTPS reverse proxy is wired up. Also fixed pragma order in db/client.ts: busy_timeout must be set before journal_mode, since switching to WAL itself takes a momentary exclusive lock that isn't covered by a busy_timeout set afterward — caused an intermittent SQLITE_BUSY during `next build`'s parallel page-data collection. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012o9j9RezxbZVKQMrB7oRLY
This commit is contained in:
1 parent
fa7bda7a0f
commit
14fe8c0445
2 files changed
+11
-7
No files matched your search
@@ -46,7 +46,12 @@ export async function setSessionCookie(token: string): Promise<void> {
|
|||||||
const cookieStore = await cookies();
|
const cookieStore = await cookies();
|
||||||
cookieStore.set(SESSION_COOKIE, token, {
|
cookieStore.set(SESSION_COOKIE, token, {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: process.env.NODE_ENV === "production",
|
// Secure by default in production. Set COOKIE_ALLOW_INSECURE=true only
|
||||||
|
// for temporary testing over plain HTTP (e.g. mid-migration before the
|
||||||
|
// HTTPS reverse proxy is wired up) — a Secure cookie is silently
|
||||||
|
// dropped by the browser over HTTP, which looks exactly like "login
|
||||||
|
// accepts the password but you're bounced straight back to /login".
|
||||||
|
secure: process.env.NODE_ENV === "production" && process.env.COOKIE_ALLOW_INSECURE !== "true",
|
||||||
sameSite: "lax",
|
sameSite: "lax",
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: SESSION_TTL_MS / 1000,
|
maxAge: SESSION_TTL_MS / 1000,
|
||||||
|
|||||||
@@ -8,14 +8,13 @@ const dataDir = process.env.DATA_DIR ?? path.join(process.cwd(), "data");
|
|||||||
fs.mkdirSync(dataDir, { recursive: true });
|
fs.mkdirSync(dataDir, { recursive: true });
|
||||||
|
|
||||||
const sqlite = new Database(path.join(dataDir, "db.sqlite"));
|
const sqlite = new Database(path.join(dataDir, "db.sqlite"));
|
||||||
|
// busy_timeout MUST be set before journal_mode: switching to WAL itself
|
||||||
|
// takes a momentary exclusive lock, and if a concurrent worker is mid-switch
|
||||||
|
// on a fresh db.sqlite, that first statement has no busy_timeout protection
|
||||||
|
// yet and throws SQLITE_BUSY immediately instead of waiting.
|
||||||
|
sqlite.pragma("busy_timeout = 30000");
|
||||||
sqlite.pragma("journal_mode = WAL");
|
sqlite.pragma("journal_mode = WAL");
|
||||||
sqlite.pragma("foreign_keys = ON");
|
sqlite.pragma("foreign_keys = ON");
|
||||||
// Next's build-time page-data collection evaluates route modules across
|
|
||||||
// several worker processes concurrently — without this, two workers
|
|
||||||
// racing to open/initialize a fresh db.sqlite can throw SQLITE_BUSY
|
|
||||||
// instead of just waiting for the other's lock to clear. 5s wasn't enough
|
|
||||||
// once the route count grew — bumped to 30s (build-time only cost).
|
|
||||||
sqlite.pragma("busy_timeout = 30000");
|
|
||||||
|
|
||||||
export const db = drizzle(sqlite, { schema });
|
export const db = drizzle(sqlite, { schema });
|
||||||
export type DB = typeof db;
|
export type DB = typeof db;
|
||||||
Reference in new issue
Block a user