chore: harden deps, env validation, admin errors, and redis warnings
Align nodemailer with Auth.js peers, bump patch deps, validate env on deploy builds, add admin error boundary, and warn when Redis is missing in production. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
c865e6f699
commit
c46dadeda4
10 files changed
+876
-461
No files matched your search
@@ -13,7 +13,8 @@ describe("production deploy workflow", () => {
|
||||
expect(workflow).not.toMatch(/rm\s+-rf\s+\.next(?:\s|$)/);
|
||||
expect(workflow).toContain("rm -rf .output dist .next/types .next/dev");
|
||||
expect(workflow).toContain("pnpm install --frozen-lockfile");
|
||||
expect(workflow).toContain("SKIP_ENV_VALIDATION=1");
|
||||
// Production builds must validate env (AUTH_SECRET, DATABASE_URL, …).
|
||||
expect(workflow).not.toContain("SKIP_ENV_VALIDATION=1");
|
||||
});
|
||||
|
||||
it("reclaims ownership before git reset so www-data files can be overwritten", () => {
|
||||
|
||||
@@ -13,6 +13,7 @@ const CLEANUP_INTERVAL_MS = 300_000;
|
||||
const MAX_BUCKETS = 10_000;
|
||||
|
||||
let lastCleanup = Date.now();
|
||||
let redisFailWarned = false;
|
||||
|
||||
function cleanup(): void {
|
||||
const now = Date.now();
|
||||
@@ -54,6 +55,12 @@ export async function rateLimit(
|
||||
return { ok: true, retryAfter: 0 };
|
||||
} catch {
|
||||
// Redis unavailable — fall through to in-memory
|
||||
if (process.env.NODE_ENV === "production" && !redisFailWarned) {
|
||||
redisFailWarned = true;
|
||||
console.error(
|
||||
"[rate-limit] Redis error — falling back to in-process buckets. Limits are not shared across instances until Redis recovers.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-2
@@ -2,11 +2,25 @@ import "server-only";
|
||||
|
||||
import Redis from "ioredis";
|
||||
|
||||
const globalForRedis = globalThis as unknown as { redis?: Redis | null };
|
||||
const globalForRedis = globalThis as unknown as {
|
||||
redis?: Redis | null;
|
||||
redisMissingWarned?: boolean;
|
||||
};
|
||||
|
||||
function createRedis(): Redis | null {
|
||||
const url = process.env.REDIS_URL;
|
||||
if (!url) return null;
|
||||
if (!url) {
|
||||
if (
|
||||
process.env.NODE_ENV === "production" &&
|
||||
!globalForRedis.redisMissingWarned
|
||||
) {
|
||||
globalForRedis.redisMissingWarned = true;
|
||||
console.error(
|
||||
"[redis] REDIS_URL is unset in production. Rate limits and shared caches fall back to in-process memory and will not work correctly across multiple instances.",
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const client = new Redis(url, {
|
||||
maxRetriesPerRequest: 3,
|
||||
|
||||
Reference in new issue
Block a user