Codebase audit: remove dead code, fix broken patterns, consolidate duplicates; v2.0.27
Publish Container / docker (push) Failing after 10m40s

- Remove unused prop-types dep, deprecated useOutboundLinkTracking export
- Fix missing linkClicks key in analyticsEvents initial state (B-01)
- Export ADMIN_SESSION_COOKIE from auth.js; remove local copy in admin-auth.js (D-02)
- Remove cookieFlags() wrapper in auth.js and study-helpers.js; use cookieSecureFlag() directly (U-04)
- Remove ADMIN_SESSION_TTL_MS duplicate from config.js (D-01)
- Remove DEFAULT_SEO/DEFAULT_LEGAL/DEFAULT_REDIRECT_RULES/DEFAULT_PODCAST_FEATURED_LINKS/DEFAULT_PUBLISH_STATE
  duplicates from config.js; re-export from helpers.js (D-04, fixes sitemapPaths divergence)
- Fix email.js hardcoded fallback strings to use DEFAULT_RESEND_TO/DEFAULT_RESEND_REPLY_TO (M-02)
- Remove duplicate normalizeIp, isPrivateOrLocalIp, normalizeRedirectPath, sanitizeUrl,
  sanitizeRedirectRules bodies from study-helpers.js; re-export from helpers.js (D-03)
- Fix pruneStatsByDays to import VISITOR_RETENTION_DAYS_DEFAULT from config.js (B-02)
- Fix createTitusDownloadToken to use DOWNLOAD_TOKEN_TTL_MS constant (B-03)
- Remove normalizeMessageType duplicate from study-helpers.js (U-03/D-08)
- Remove dead wantsWelcome variable in contact.js; use shouldSendWelcome (B-04)
- Replace dynamic imports in contact.js with static imports (B-07)
- Remove dead wantsWelcome=true in study-auth.js (B-05)
- Merge duplicate import blocks in analytics.js and public.js (D-05, D-06)
- Replace dynamic readFile re-import in nuggets-host-upload.js (B-06)
- Replace hardcoded SITE_URL fallbacks with getCanonicalBaseUrl() (M-06)
- Replace raw resend.emails.send in study-account.js with sendResendEmailWithRetry (M-01)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 4.6 committed 2026-09-17 16:10:31 -04:00
1 parent 1ddb8ee7be
commit e158e1e53a
14 files changed
+58 -185

No files matched your search

+15 -82
View File
@@ -1,6 +1,15 @@
import { createHash, createHmac, randomUUID } from 'node:crypto'
import path from 'node:path'
import { parseCookies, cookieSecureFlag } from './helpers.js'
import {
parseCookies,
cookieSecureFlag,
normalizeIp,
isPrivateOrLocalIp,
normalizeRedirectPath,
sanitizeUrl,
sanitizeRedirectRules,
} from './helpers.js'
export { normalizeIp, isPrivateOrLocalIp, normalizeRedirectPath, sanitizeUrl, sanitizeRedirectRules } from './helpers.js'
import {
STUDY_SESSION_COOKIE,
STUDY_SESSION_TTL_MS,
@@ -9,6 +18,8 @@ import {
EMAIL_OTP_MAX_ATTEMPTS,
CONTACT_EMAIL_COOLDOWN_MS,
DEFAULT_REDIRECT_RULES,
VISITOR_RETENTION_DAYS_DEFAULT,
DOWNLOAD_TOKEN_TTL_MS,
} from './config.js'
import { state } from './state.js'
import { queueStudyRemindersWrite, queueStudyUsersWrite } from './data.js'
@@ -130,10 +141,6 @@ export function getStudyAvatarUrl(subject) {
// ── Session management ─────────────────────────────────────────────────────
export function cookieFlags() {
return cookieSecureFlag()
}
export function createStudySession(userId) {
const token = randomUUID()
state.studySessions.set(token, { userId, expiresAt: Date.now() + STUDY_SESSION_TTL_MS })
@@ -143,14 +150,14 @@ export function createStudySession(userId) {
export function setStudySessionCookie(res, token) {
res.append(
'Set-Cookie',
`${STUDY_SESSION_COOKIE}=${encodeURIComponent(token)}; Max-Age=${Math.floor(STUDY_SESSION_TTL_MS / 1000)}; Path=/; HttpOnly; SameSite=Lax${cookieFlags()}`,
`${STUDY_SESSION_COOKIE}=${encodeURIComponent(token)}; Max-Age=${Math.floor(STUDY_SESSION_TTL_MS / 1000)}; Path=/; HttpOnly; SameSite=Lax${cookieSecureFlag()}`,
)
}
export function clearStudySessionCookie(res) {
res.append(
'Set-Cookie',
`${STUDY_SESSION_COOKIE}=; Max-Age=0; Path=/; HttpOnly; SameSite=Lax${cookieFlags()}`,
`${STUDY_SESSION_COOKIE}=; Max-Age=0; Path=/; HttpOnly; SameSite=Lax${cookieSecureFlag()}`,
)
}
@@ -233,7 +240,7 @@ export function createTitusDownloadToken(email) {
const token = randomUUID()
state.titusDownloadTokens.set(token, {
email,
expiresAt: Date.now() + (10 * 60 * 1000),
expiresAt: Date.now() + DOWNLOAD_TOKEN_TTL_MS,
})
return token
}
@@ -381,29 +388,6 @@ export function detectBot(userAgent) {
return { isBot: false, reason: null }
}
export function normalizeIp(rawIp) {
if (!rawIp) return 'unknown'
let ip = String(rawIp).trim()
if (ip.includes(',')) ip = ip.split(',')[0].trim()
if (ip.startsWith('::ffff:')) ip = ip.slice(7)
if (ip === '::1') ip = '127.0.0.1'
return ip || 'unknown'
}
export function isPrivateOrLocalIp(ip) {
return (
ip === '127.0.0.1'
|| ip === 'localhost'
|| ip.startsWith('10.')
|| ip.startsWith('192.168.')
|| /^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(ip)
|| ip.startsWith('fc')
|| ip.startsWith('fd')
|| ip.startsWith('fe80:')
|| ip === 'unknown'
)
}
export function buildTopLocations(list, key) {
const counts = {}
for (const row of list) {
@@ -455,7 +439,6 @@ export function recordHit(pathname, isBot = false, botReason = null) {
}
export function pruneStatsByDays(daysRaw) {
const { VISITOR_RETENTION_DAYS_DEFAULT, EMPTY_HIT_STATS: _unused } = { VISITOR_RETENTION_DAYS_DEFAULT: 180 }
const days = Number(daysRaw)
const retentionDays = Number.isFinite(days) && days > 0 ? Math.floor(days) : 180
const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000
@@ -505,51 +488,6 @@ export function pruneStatsByDays(daysRaw) {
}
}
// ── Redirect / URL helpers ─────────────────────────────────────────────────
export function normalizeRedirectPath(value) {
if (typeof value !== 'string') return ''
const trimmed = value.trim()
if (!trimmed) return ''
const withSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`
const normalized = withSlash.replace(/\/+/g, '/')
if (normalized === '/') return ''
if (normalized.startsWith('/api/') || normalized.startsWith('/admin')) return ''
return normalized
}
export function sanitizeUrl(value) {
if (typeof value !== 'string') return ''
const trimmed = value.trim()
if (!trimmed) return ''
if (trimmed.startsWith('/')) return trimmed
if (/^https?:\/\//i.test(trimmed)) return trimmed
return ''
}
export function sanitizeRedirectRules(value) {
const source = Array.isArray(value) ? value : []
const seen = new Set()
const out = []
for (const item of source) {
const pathValue = normalizeRedirectPath(item?.path)
const target = sanitizeUrl(item?.target)
const statusCode = Number(item?.statusCode) === 302 ? 302 : 301
if (!pathValue || !target) continue
if (seen.has(pathValue)) continue
seen.add(pathValue)
out.push({
id: typeof item?.id === 'string' && item.id.trim() ? item.id.trim() : randomUUID(),
path: pathValue,
target,
statusCode,
})
}
return out.length > 0 ? out : DEFAULT_REDIRECT_RULES
}
// ── Contact / email tracking ───────────────────────────────────────────────
export function noteContactEmailCooldown(emailAddress) {
@@ -609,11 +547,6 @@ export function extractResendMessageId(result) {
return ''
}
export function normalizeMessageType(value) {
if (value === 'question' || value === 'testimony' || value === 'topic') return value
return 'general'
}
// ── Study reminder scheduler ───────────────────────────────────────────────
export async function scheduleStudyReminders(sendStudyReminderEmail) {