← back to jryan5150__heaton-web-directory-prod

Function bodies 115 total

All specs Real LLM only Function bodies
main function · typescript · L10-L152 (143 LOC)
scripts/migrate-to-database.ts
async function main() {
  console.log('Starting database migration...\n')

  // 1. Migrate Employees
  console.log('📋 Migrating employees...')
  const employeesPath = path.join(process.cwd(), 'data', 'employees.json')
  const employeesData = JSON.parse(fs.readFileSync(employeesPath, 'utf-8'))

  let employeeCount = 0
  for (const emp of employeesData) {
    await prisma.employee.upsert({
      where: { id: emp.id },
      update: {
        firstName: emp.firstName,
        lastName: emp.lastName,
        email: emp.email || null,
        extension: emp.extension || null,
        phoneNumber: emp.phoneNumber || null,
        did: emp.did || null,
        location: emp.location || 'Unknown',
        team: emp.team || emp.department || 'General',
        title: emp.title || null,
        jobTitle: emp.jobTitle || null,
        department: emp.department || null,
        photoUrl: emp.photoUrl || null,
        avatarUrl: emp.avatarUrl || null,
      },
      create: {
        id: emp.id,
 
log function · typescript · L43-L46 (4 LOC)
scripts/nextiva-scraper.ts
function log(message: string): void {
  const timestamp = new Date().toISOString()
  console.log(`[${timestamp}] ${message}`)
}
logError function · typescript · L48-L51 (4 LOC)
scripts/nextiva-scraper.ts
function logError(message: string): void {
  const timestamp = new Date().toISOString()
  console.error(`[${timestamp}] ERROR: ${message}`)
}
validateEnv function · typescript · L53-L73 (21 LOC)
scripts/nextiva-scraper.ts
function validateEnv(): Record<(typeof REQUIRED_ENV_VARS)[number], string> {
  const missing: string[] = []
  const env: Record<string, string> = {}

  for (const key of REQUIRED_ENV_VARS) {
    const value = process.env[key]
    if (!value || value.trim().length === 0) {
      missing.push(key)
    } else {
      env[key] = value.trim()
    }
  }

  if (missing.length > 0) {
    throw new Error(
      `Missing required environment variables: ${missing.join(', ')}`
    )
  }

  return env as Record<(typeof REQUIRED_ENV_VARS)[number], string>
}
ensureScreenshotDir function · typescript · L75-L79 (5 LOC)
scripts/nextiva-scraper.ts
function ensureScreenshotDir(): void {
  if (!existsSync(SCREENSHOT_DIR)) {
    mkdirSync(SCREENSHOT_DIR, { recursive: true })
  }
}
takeScreenshot function · typescript · L81-L95 (15 LOC)
scripts/nextiva-scraper.ts
async function takeScreenshot(
  page: Page,
  name: string
): Promise<string | null> {
  try {
    ensureScreenshotDir()
    const filepath = join(SCREENSHOT_DIR, `${name}.png`)
    await page.screenshot({ path: filepath, fullPage: true })
    log(`Screenshot saved: ${filepath}`)
    return filepath
  } catch (err) {
    logError(`Failed to take screenshot "${name}": ${err}`)
    return null
  }
}
login function · typescript · L101-L203 (103 LOC)
scripts/nextiva-scraper.ts
async function login(
  page: Page,
  username: string,
  password: string
): Promise<void> {
  let lastError: Error | null = null

  for (let attempt = 1; attempt <= MAX_LOGIN_ATTEMPTS; attempt++) {
    log(`Login attempt ${attempt}/${MAX_LOGIN_ATTEMPTS}...`)

    try {
      await page.goto(LOGIN_URL, {
        waitUntil: 'networkidle',
        timeout: NAVIGATION_TIMEOUT_MS,
      })

      log('Login page loaded, filling credentials...')

      // Nextiva login form — wait for the email/username input
      // The login form may use different selectors; try common patterns
      const emailSelector = await page
        .waitForSelector(
          'input[type="email"], input[name="username"], input[name="email"], input#email, input#username',
          { timeout: LOGIN_TIMEOUT_MS }
        )

      if (!emailSelector) {
        throw new Error('Could not find email/username input field')
      }

      await emailSelector.fill(username)
      log('Username entered')

      // Some l
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
navigateToUsersPage function · typescript · L209-L276 (68 LOC)
scripts/nextiva-scraper.ts
async function navigateToUsersPage(page: Page): Promise<void> {
  log('Navigating to Users management page...')

  // Try direct URL navigation first (most Nextiva admin portals use this path)
  const usersUrls = [
    'https://admin.nextiva.com/users',
    'https://admin.nextiva.com/#/users',
    'https://admin.nextiva.com/management/users',
  ]

  for (const url of usersUrls) {
    try {
      await page.goto(url, {
        waitUntil: 'networkidle',
        timeout: NAVIGATION_TIMEOUT_MS,
      })

      // Check if we landed on a page with user-related content
      const hasUsersContent = await page
        .waitForSelector(
          'text=Users, text=User Management, [data-testid="users"], table',
          { timeout: 10_000 }
        )
        .catch(() => null)

      if (hasUsersContent) {
        log(`Users page loaded via direct URL: ${url}`)
        return
      }
    } catch {
      // Try next URL
    }
  }

  // Fallback: navigate via the sidebar/menu
  log('Direct URL n
exportUsersCSV function · typescript · L278-L358 (81 LOC)
scripts/nextiva-scraper.ts
async function exportUsersCSV(page: Page): Promise<string> {
  log('Looking for CSV export button...')

  // Common export button selectors for Nextiva admin
  const exportSelectors = [
    'button:has-text("Export")',
    'button:has-text("Download")',
    'button:has-text("Export CSV")',
    'button:has-text("Download CSV")',
    'a:has-text("Export")',
    'a:has-text("Download")',
    '[data-testid="export"]',
    '[data-testid="export-csv"]',
    '[aria-label="Export"]',
    '[aria-label="Download"]',
    'button >> svg', // Icon-only export buttons
  ]

  let exportButton = null

  for (const selector of exportSelectors) {
    try {
      exportButton = await page.waitForSelector(selector, {
        timeout: 5_000,
      })
      if (exportButton) {
        log(`Found export button with selector: ${selector}`)
        break
      }
    } catch {
      // Try next selector
    }
  }

  if (!exportButton) {
    await takeScreenshot(page, 'export-button-not-found')
    throw new Err
uploadCSV function · typescript · L364-L398 (35 LOC)
scripts/nextiva-scraper.ts
async function uploadCSV(
  csvContent: string,
  uploadUrl: string,
  syncSecret: string
): Promise<void> {
  log(`Uploading CSV to ${uploadUrl}...`)

  const response = await fetch(uploadUrl, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${syncSecret}`,
      'Content-Type': 'text/csv',
    },
    body: csvContent,
  })

  const responseText = await response.text()

  if (!response.ok) {
    logError(`Sync endpoint returned ${response.status}: ${responseText}`)
    throw new Error(
      `Sync upload failed with status ${response.status}: ${responseText}`
    )
  }

  // Try to parse as JSON for structured logging
  try {
    const result = JSON.parse(responseText)
    log(`Sync result: ${JSON.stringify(result, null, 2)}`)
  } catch {
    log(`Sync response: ${responseText}`)
  }

  log('CSV uploaded successfully')
}
main function · typescript · L404-L462 (59 LOC)
scripts/nextiva-scraper.ts
async function main(): Promise<void> {
  log('=== Nextiva CSV Sync — Starting ===')

  // Validate environment
  const env = validateEnv()
  log('Environment variables validated')

  let browser: Browser | null = null

  try {
    // Launch browser
    log('Launching Chromium (headless)...')
    browser = await chromium.launch({
      headless: true,
    })

    const context = await browser.newContext({
      acceptDownloads: true,
      viewport: { width: 1280, height: 720 },
      userAgent:
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    })

    const page = await context.newPage()

    // Set default timeouts
    page.setDefaultTimeout(NAVIGATION_TIMEOUT_MS)
    page.setDefaultNavigationTimeout(NAVIGATION_TIMEOUT_MS)

    // Step 1: Login
    await login(page, env.NEXTIVA_USERNAME, env.NEXTIVA_PASSWORD)

    // Step 2: Navigate to Users page
    await navigateToUsersPage(page)

    // Step 3: Export CSV
main function · typescript · L16-L29 (14 LOC)
scripts/seed-allowed-ips.ts
async function main() {
  console.log('Seeding allowed IPs...')

  for (const entry of OFFICE_IPS) {
    await prisma.allowedIP.upsert({
      where: { ip: entry.ip },
      update: { location: entry.location, notes: entry.notes },
      create: { ...entry, addedBy: 'system-seed' },
    })
    console.log(`  ✓ ${entry.ip} (${entry.location})`)
  }

  console.log(`\nSeeded ${OFFICE_IPS.length} IPs.`)
}
getErrorMessage function · typescript · L9-L25 (17 LOC)
src/app/admin/login/page.tsx
function getErrorMessage(code: string | null): string {
  switch (code) {
    case 'AccessDenied':
      return 'Access denied. Your Microsoft account is not registered as an admin.'
    case 'NoSession':
      return 'Microsoft sign-in session expired. Please try again.'
    case 'NotRegistered':
      return 'Your account is not registered as an admin. Contact your administrator.'
    case 'CallbackError':
      return 'Something went wrong during sign-in. Please try again.'
    case 'OAuthSignin':
    case 'OAuthCallback':
      return 'Microsoft sign-in failed. Please try again.'
    default:
      return code ? 'Sign-in failed. Please try again.' : ''
  }
}
AdminLoginPage function · typescript · L31-L47 (17 LOC)
src/app/admin/login/page.tsx
export default function AdminLoginPage() {
  return (
    <Suspense fallback={
      <div style={{
        minHeight: '100vh',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        background: 'linear-gradient(135deg, #0a1f38 0%, #0f2b4c 50%, #163d6b 100%)',
      }}>
        <div style={{ color: 'rgba(255,255,255,0.5)', fontSize: '14px' }}>Loading...</div>
      </div>
    }>
      <LoginContent />
    </Suspense>
  )
}
LoginContent function · typescript · L49-L372 (324 LOC)
src/app/admin/login/page.tsx
function LoginContent() {
  const router = useRouter()
  const searchParams = useSearchParams()
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [error, setError] = useState(() => getErrorMessage(searchParams.get('error')))
  const [loading, setLoading] = useState(false)
  const [msLoading, setMsLoading] = useState(false)

  const handleMicrosoftSignIn = async () => {
    setError('')
    setMsLoading(true)
    try {
      await signIn('azure-ad', {
        callbackUrl: '/api/admin/microsoft-callback',
      })
    } catch {
      setError('Failed to initiate Microsoft sign-in.')
      setMsLoading(false)
    }
  }

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    setError('')
    setLoading(true)

    try {
      const response = await fetch('/api/admin/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password })
      })

    
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
AdminPage function · typescript · L3-L5 (3 LOC)
src/app/admin/page.tsx
export default function AdminPage() {
  return <AdminDashboard />
}
GET function · typescript · L5-L18 (14 LOC)
src/app/api/admin/activity/route.ts
export async function GET() {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    // Activity log not yet migrated to database — return empty for now
    return NextResponse.json([])
  } catch (error) {
    console.error('Error reading activity log:', error)
    return NextResponse.json({ error: 'Failed to fetch activity log' }, { status: 500 })
  }
}
GET function · typescript · L6-L32 (27 LOC)
src/app/api/admin/ips/route.ts
export async function GET() {
  try {
    const user = await getSessionFromCookie()

    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const allowedIPs = await prisma.allowedIP.findMany({
      orderBy: { addedAt: 'desc' }
    })

    const mapped = allowedIPs.map((record) => ({
      id: record.id,
      ip: record.ip,
      location: record.location,
      notes: record.notes,
      addedBy: record.addedBy,
      addedAt: record.addedAt.toISOString()
    }))

    return NextResponse.json(mapped)
  } catch (error) {
    console.error('Error fetching allowed IPs:', error)
    return NextResponse.json({ error: 'Failed to fetch allowed IPs' }, { status: 500 })
  }
}
POST function · typescript · L35-L100 (66 LOC)
src/app/api/admin/ips/route.ts
export async function POST(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()

    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    if (!isSuperAdmin(user)) {
      return NextResponse.json({ error: 'Forbidden - Superadmin only' }, { status: 403 })
    }

    const { ip, location, notes } = await request.json()

    if (!ip || !location) {
      return NextResponse.json({ error: 'Missing required fields (ip, location)' }, { status: 400 })
    }

    // Validate IPv4 format
    const parts = ip.split('.')
    if (parts.length !== 4) {
      return NextResponse.json({ error: 'Invalid IPv4 format' }, { status: 400 })
    }
    const isValidIPv4 = parts.every((part: string) => {
      const num = parseInt(part, 10)
      return !isNaN(num) && num >= 0 && num <= 255 && String(num) === part
    })
    if (!isValidIPv4) {
      return NextResponse.json({ error: 'Invalid IPv4 format' }, { status: 400 })
    }

    // 
DELETE function · typescript · L103-L139 (37 LOC)
src/app/api/admin/ips/route.ts
export async function DELETE(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()

    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    if (!isSuperAdmin(user)) {
      return NextResponse.json({ error: 'Forbidden - Superadmin only' }, { status: 403 })
    }

    const { searchParams } = new URL(request.url)
    const id = searchParams.get('id')

    if (!id) {
      return NextResponse.json({ error: 'IP id is required as query parameter' }, { status: 400 })
    }

    const existing = await prisma.allowedIP.findUnique({
      where: { id }
    })

    if (!existing) {
      return NextResponse.json({ error: 'IP record not found' }, { status: 404 })
    }

    await prisma.allowedIP.delete({
      where: { id }
    })

    return NextResponse.json({ success: true })
  } catch (error) {
    console.error('Error deleting allowed IP:', error)
    return NextResponse.json({ error: 'Failed to delete allowed IP' }, { 
POST function · typescript · L6-L75 (70 LOC)
src/app/api/admin/login/route.ts
export async function POST(request: NextRequest) {
  try {
    const { email, password } = await request.json()

    if (!email || !password) {
      return NextResponse.json(
        { error: 'Email and password are required' },
        { status: 400 }
      )
    }

    const user = await prisma.user.findFirst({
      where: {
        email: {
          equals: email,
          mode: 'insensitive'
        }
      }
    })

    if (!user) {
      return NextResponse.json(
        { error: 'Invalid email or password' },
        { status: 401 }
      )
    }

    // SSO-only users don't have a password -- they must use Microsoft sign-in
    if (!user.passwordHash) {
      return NextResponse.json(
        { error: 'This account uses Microsoft sign-in. Please use the "Sign in with Microsoft" button.' },
        { status: 401 }
      )
    }

    // Verify password
    const isValid = await verifyPassword(password, user.passwordHash)

    if (!isValid) {
      return NextResponse.json(
  
POST function · typescript · L4-L16 (13 LOC)
src/app/api/admin/logout/route.ts
export async function POST() {
  try {
    await clearSessionCookie()

    return NextResponse.json({ success: true })
  } catch (error) {
    console.error('Logout error:', error)
    return NextResponse.json(
      { error: 'Logout failed' },
      { status: 500 }
    )
  }
}
GET function · typescript · L13-L65 (53 LOC)
src/app/api/admin/microsoft-callback/route.ts
export async function GET(request: NextRequest) {
  try {
    // Get the next-auth session (contains Microsoft profile data)
    const session = await auth()

    if (!session?.user?.email) {
      const loginUrl = new URL('/admin/login', request.url)
      loginUrl.searchParams.set('error', 'NoSession')
      return NextResponse.redirect(loginUrl)
    }

    // Look up the user in our User table by email (case-insensitive)
    const dbUser = await prisma.user.findFirst({
      where: {
        email: {
          equals: session.user.email,
          mode: 'insensitive',
        },
      },
    })

    if (!dbUser) {
      const loginUrl = new URL('/admin/login', request.url)
      loginUrl.searchParams.set('error', 'NotRegistered')
      return NextResponse.redirect(loginUrl)
    }

    // Update microsoftId if not already set
    const microsoftId = session.microsoftId
    if (microsoftId && !dbUser.microsoftId) {
      await prisma.user.update({
        where: { id: dbUser.id },
   
Repobility · code-quality intelligence platform · https://repobility.com
GET function · typescript · L5-L138 (134 LOC)
src/app/api/admin/notify-approved/route.ts
export async function GET(request: NextRequest) {
  try {
    // Verify cron secret for Vercel cron jobs, or reject unauthenticated calls
    const authHeader = request.headers.get('authorization')
    const cronSecret = process.env.CRON_SECRET
    if (cronSecret && authHeader !== `Bearer ${cronSecret}`) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const resend = new Resend(process.env.RESEND_API_KEY)
    // Read approved changes from database
    const approvedChanges = await prisma.pendingChange.findMany({
      where: { status: 'approved' }
    })

    if (approvedChanges.length === 0) {
      return NextResponse.json({
        success: true,
        message: 'No approved changes to notify about',
        sent: false
      })
    }

    // Count changes by type
    const changesByType = {
      add: approvedChanges.filter(c => c.type === 'add').length,
      edit: approvedChanges.filter(c => c.type === 'edit').length,
      delete: approved
mapToPendingChange function · typescript · L8-L34 (27 LOC)
src/app/api/admin/pending/route.ts
function mapToPendingChange(dbChange: {
  id: string
  type: string
  employeeId: string | null
  beforeData: unknown
  afterData: unknown
  status: string
  proposedBy: string
  proposedAt: Date
  approvedBy: string | null
  approvedAt: Date | null
  notes: string | null
}): PendingChange {
  return {
    id: dbChange.id,
    type: dbChange.type as 'add' | 'edit' | 'delete',
    employeeId: dbChange.employeeId || undefined,
    before: dbChange.beforeData as Employee | undefined,
    after: dbChange.afterData as Employee | undefined,
    status: dbChange.status as 'pending' | 'approved' | 'rejected',
    proposedBy: dbChange.proposedBy,
    proposedAt: dbChange.proposedAt.toISOString(),
    approvedBy: dbChange.approvedBy || undefined,
    approvedAt: dbChange.approvedAt?.toISOString(),
    notes: dbChange.notes || undefined,
  }
}
GET function · typescript · L37-L52 (16 LOC)
src/app/api/admin/pending/route.ts
export async function GET() {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const changes = await prisma.pendingChange.findMany({
      orderBy: { proposedAt: 'desc' }
    })
    return NextResponse.json(changes.map(mapToPendingChange))
  } catch (error) {
    console.error('Error fetching pending changes:', error)
    return NextResponse.json({ error: 'Failed to fetch pending changes' }, { status: 500 })
  }
}
POST function · typescript · L55-L85 (31 LOC)
src/app/api/admin/pending/route.ts
export async function POST(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const change: PendingChange = await request.json()

    const newChange = await prisma.pendingChange.create({
      data: {
        id: `change-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
        type: change.type,
        employeeId: change.employeeId || null,
        beforeData: change.before ? (change.before as object) : undefined,
        afterData: change.after ? (change.after as object) : undefined,
        status: change.status || 'pending',
        proposedBy: change.proposedBy,
        proposedAt: change.proposedAt ? new Date(change.proposedAt) : new Date(),
        approvedBy: change.approvedBy || null,
        approvedAt: change.approvedAt ? new Date(change.approvedAt) : null,
        notes: change.notes || null,
      }
    })

    return NextResponse.jso
PATCH function · typescript · L88-L119 (32 LOC)
src/app/api/admin/pending/route.ts
export async function PATCH(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }
    if (!canApprove(user)) {
      return NextResponse.json({ error: 'Forbidden - Approver or Super Admin only' }, { status: 403 })
    }

    const { id, status, notes, approvedBy, approvedAt } = await request.json()

    if (!id) {
      return NextResponse.json({ error: 'ID required' }, { status: 400 })
    }

    const updatedChange = await prisma.pendingChange.update({
      where: { id },
      data: {
        status,
        notes: notes || undefined,
        approvedBy: approvedBy || undefined,
        approvedAt: approvedAt ? new Date(approvedAt) : undefined,
      }
    })

    return NextResponse.json(mapToPendingChange(updatedChange))
  } catch (error) {
    console.error('Error updating pending change:', error)
    return NextResponse.json({ error: 'Failed to update pendin
DELETE function · typescript · L122-L145 (24 LOC)
src/app/api/admin/pending/route.ts
export async function DELETE(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const { searchParams } = new URL(request.url)
    const id = searchParams.get('id')

    if (!id) {
      return NextResponse.json({ error: 'ID required' }, { status: 400 })
    }

    await prisma.pendingChange.delete({
      where: { id }
    })

    return NextResponse.json({ success: true })
  } catch (error) {
    console.error('Error deleting pending change:', error)
    return NextResponse.json({ error: 'Failed to delete pending change' }, { status: 500 })
  }
}
POST function · typescript · L7-L150 (144 LOC)
src/app/api/admin/publish/route.ts
export async function POST(request: NextRequest) {
  try {
    // Check authentication and authorization
    const user = await getSessionFromCookie()

    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    if (!canPublish(user)) {
      return NextResponse.json({ error: 'Forbidden - Super Admin only' }, { status: 403 })
    }

    const { author = user.name || 'Admin' } = await request.json()

    // Get approved changes from database
    const approvedChanges = await prisma.pendingChange.findMany({
      where: { status: 'approved' }
    })

    if (approvedChanges.length === 0) {
      return NextResponse.json({
        error: 'No approved changes to publish'
      }, { status: 400 })
    }

    // Load current employees from database
    const currentEmployees = await prisma.employee.findMany()
    const employeeMap = new Map(currentEmployees.map(e => [e.id, e]))

    // Create version snapshot BEFORE applying changes
    const versio
POST function · typescript · L7-L107 (101 LOC)
src/app/api/admin/rollback/route.ts
export async function POST(request: NextRequest) {
  try {
    // Check authentication and authorization
    const user = await getSessionFromCookie()

    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    if (!canPublish(user)) {
      return NextResponse.json({ error: 'Forbidden - Super Admin only' }, { status: 403 })
    }

    const { versionId, author = user.name || 'Admin' } = await request.json()

    if (!versionId) {
      return NextResponse.json({ error: 'Version ID required' }, { status: 400 })
    }

    // Find the version in database
    const version = await prisma.version.findFirst({
      where: { versionId }
    })

    if (!version) {
      return NextResponse.json({ error: 'Version not found' }, { status: 404 })
    }

    // Get current employees for backup
    const currentEmployees = await prisma.employee.findMany()
    const currentSnapshot = currentEmployees.map(emp => ({
      id: emp.id,
      firstName: emp.f
All rows above produced by Repobility · https://repobility.com
GET function · typescript · L4-L23 (20 LOC)
src/app/api/admin/session/route.ts
export async function GET() {
  try {
    const user = await getSessionFromCookie()

    if (!user) {
      return NextResponse.json(
        { error: 'Not authenticated' },
        { status: 401 }
      )
    }

    return NextResponse.json(user)
  } catch (error) {
    console.error('Session error:', error)
    return NextResponse.json(
      { error: 'Failed to get session' },
      { status: 500 }
    )
  }
}
GET function · typescript · L15-L55 (41 LOC)
src/app/api/admin/sync/mappings/route.ts
export async function GET() {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const mappings = await prisma.syncMapping.findMany({
      orderBy: { addedAt: 'desc' },
    })

    // Batch-fetch employee names for all mapped IDs
    const employeeIds = mappings.map((m) => m.employeeId)
    const employees = await prisma.employee.findMany({
      where: { id: { in: employeeIds } },
      select: { id: true, firstName: true, lastName: true },
    })

    const employeeMap = new Map(
      employees.map((e) => [e.id, `${e.firstName} ${e.lastName}`])
    )

    return NextResponse.json(
      mappings.map((m) => ({
        id: m.id,
        nextivaEmail: m.nextivaEmail,
        employeeId: m.employeeId,
        employeeName: employeeMap.get(m.employeeId) ?? '(employee not found)',
        addedBy: m.addedBy,
        addedAt: m.addedAt.toISOString(),
        notes: m.notes,
      }))
POST function · typescript · L57-L133 (77 LOC)
src/app/api/admin/sync/mappings/route.ts
export async function POST(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    if (!isSuperAdmin(user)) {
      return NextResponse.json(
        { error: 'Forbidden — Superadmin only' },
        { status: 403 }
      )
    }

    const { nextivaEmail, employeeId, notes } = await request.json()

    if (!nextivaEmail || !employeeId) {
      return NextResponse.json(
        { error: 'Missing required fields: nextivaEmail, employeeId' },
        { status: 400 }
      )
    }

    // Validate that the employee exists
    const employee = await prisma.employee.findUnique({
      where: { id: employeeId },
      select: { id: true, firstName: true, lastName: true },
    })

    if (!employee) {
      return NextResponse.json(
        { error: 'Employee not found' },
        { status: 404 }
      )
    }

    // Check for duplicate mapping
    const existing = awa
DELETE function · typescript · L135-L177 (43 LOC)
src/app/api/admin/sync/mappings/route.ts
export async function DELETE(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    if (!isSuperAdmin(user)) {
      return NextResponse.json(
        { error: 'Forbidden — Superadmin only' },
        { status: 403 }
      )
    }

    const { searchParams } = new URL(request.url)
    const id = searchParams.get('id')

    if (!id) {
      return NextResponse.json(
        { error: 'Mapping ID required (pass as ?id=...)' },
        { status: 400 }
      )
    }

    const mapping = await prisma.syncMapping.findUnique({ where: { id } })
    if (!mapping) {
      return NextResponse.json(
        { error: 'Mapping not found' },
        { status: 404 }
      )
    }

    await prisma.syncMapping.delete({ where: { id } })

    return NextResponse.json({ success: true })
  } catch (error) {
    console.error('Error deleting sync mapping:', error)
    return NextRespo
GET function · typescript · L16-L57 (42 LOC)
src/app/api/admin/sync/status/route.ts
export async function GET() {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const [recentLogs, mappingCount] = await Promise.all([
      prisma.syncLog.findMany({
        orderBy: { timestamp: 'desc' },
        take: 10,
      }),
      prisma.syncMapping.count(),
    ])

    const lastSync = recentLogs.length > 0 ? recentLogs[0] : null

    return NextResponse.json({
      lastSyncTimestamp: lastSync?.timestamp.toISOString() ?? null,
      mappingCount,
      recentLogs: recentLogs.map((log) => ({
        id: log.id,
        timestamp: log.timestamp.toISOString(),
        source: log.source,
        totalRows: log.totalRows,
        matched: log.matched,
        created: log.created,
        updated: log.updated,
        skipped: log.skipped,
        errors: log.errors,
        details: log.details,
        triggeredBy: log.triggeredBy,
      })),
    })
  } catch (error) {
 
authenticateRequest function · typescript · L19-L23 (5 LOC)
src/app/api/admin/sync/upload/route.ts
async function authenticateRequest(request: NextRequest): Promise<{
  authenticated: boolean
  triggeredBy: string
  source: 'manual' | 'automated'
}> {
parseCSVText function · typescript · L68-L105 (38 LOC)
src/app/api/admin/sync/upload/route.ts
function parseCSVText(csvText: string): NextivaCSVRow[] {
  const result = Papa.parse<NextivaCSVRow>(csvText, {
    header: true,
    skipEmptyLines: true,
    transformHeader: (header) => header.trim(),
  })

  if (result.errors.length > 0) {
    const criticalErrors = result.errors.filter(
      (e) => e.type !== 'FieldMismatch'
    )
    if (criticalErrors.length > 0) {
      throw new Error(
        `CSV parse errors: ${criticalErrors.map((e) => e.message).join('; ')}`
      )
    }
  }

  if (!result.data || result.data.length === 0) {
    throw new Error('CSV file is empty or contains no valid data')
  }

  // Validate that the Name column exists
  const firstRow = result.data[0]
  if (!('Name' in firstRow)) {
    // Try case-insensitive header lookup
    const headers = Object.keys(firstRow)
    const nameHeader = headers.find((h) => h.toLowerCase().trim() === 'name')
    if (!nameHeader) {
      throw new Error(
        'CSV missing required "Name" column. Found columns: ' +
  
POST function · typescript · L107-L185 (79 LOC)
src/app/api/admin/sync/upload/route.ts
export async function POST(request: NextRequest) {
  try {
    // --- Authenticate ---
    const auth = await authenticateRequest(request)
    if (!auth.authenticated) {
      return NextResponse.json(
        { error: 'Unauthorized — valid admin session or SYNC_SECRET required' },
        { status: 401 }
      )
    }

    // --- Extract CSV text from request ---
    let csvText: string

    const contentType = request.headers.get('content-type') || ''

    if (contentType.includes('multipart/form-data')) {
      // Admin UI upload — FormData with a "file" field
      const formData = await request.formData()
      const file = formData.get('file')

      if (!file || !(file instanceof File)) {
        return NextResponse.json(
          { error: 'Missing "file" field in form data' },
          { status: 400 }
        )
      }

      csvText = await file.text()
    } else if (
      contentType.includes('text/csv') ||
      contentType.includes('application/octet-stream')
    ) {
   
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
GET function · typescript · L6-L37 (32 LOC)
src/app/api/admin/users/route.ts
export async function GET() {
  try {
    const user = await getSessionFromCookie()

    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    if (!isSuperAdmin(user)) {
      return NextResponse.json({ error: 'Forbidden - Superadmin only' }, { status: 403 })
    }

    const users = await prisma.user.findMany({
      orderBy: { addedAt: 'desc' }
    })

    // Map to expected format
    const mappedUsers = users.map(u => ({
      id: u.id,
      email: u.email,
      name: u.name,
      role: u.role,
      addedAt: u.addedAt.toISOString(),
      addedBy: u.addedBy
    }))

    return NextResponse.json(mappedUsers)
  } catch (error) {
    console.error('Error reading users:', error)
    return NextResponse.json({ error: 'Failed to fetch users' }, { status: 500 })
  }
}
POST function · typescript · L40-L100 (61 LOC)
src/app/api/admin/users/route.ts
export async function POST(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()

    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    if (!isSuperAdmin(user)) {
      return NextResponse.json({ error: 'Forbidden - Superadmin only' }, { status: 403 })
    }

    const { email, name, role, password } = await request.json()

    if (!email || !name || !role || !password) {
      return NextResponse.json({ error: 'Missing required fields (email, name, role, password)' }, { status: 400 })
    }

    if (role !== 'superadmin' && role !== 'approver' && role !== 'editor') {
      return NextResponse.json({ error: 'Invalid role' }, { status: 400 })
    }

    // Check if user already exists
    const existingUser = await prisma.user.findUnique({
      where: { email }
    })

    if (existingUser) {
      return NextResponse.json({ error: 'User already exists' }, { status: 400 })
    }

    // Hash the password
    const
DELETE function · typescript · L103-L143 (41 LOC)
src/app/api/admin/users/route.ts
export async function DELETE(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()

    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    if (!isSuperAdmin(user)) {
      return NextResponse.json({ error: 'Forbidden - Superadmin only' }, { status: 403 })
    }

    const { id } = await request.json()

    if (!id) {
      return NextResponse.json({ error: 'User ID required' }, { status: 400 })
    }

    const userToDelete = await prisma.user.findUnique({
      where: { id }
    })

    if (!userToDelete) {
      return NextResponse.json({ error: 'User not found' }, { status: 404 })
    }

    // Prevent deleting yourself
    if (userToDelete.email === user.email) {
      return NextResponse.json({ error: 'Cannot delete your own account' }, { status: 400 })
    }

    await prisma.user.delete({
      where: { id }
    })

    return NextResponse.json({ success: true })
  } catch (error) {
    console.error('Error 
GET function · typescript · L6-L39 (34 LOC)
src/app/api/admin/versions/route.ts
export async function GET() {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const versions = await prisma.version.findMany({
      orderBy: { timestamp: 'desc' },
      select: {
        versionId: true,
        timestamp: true,
        author: true,
        changeCount: true,
        description: true,
        // Don't include snapshot to reduce payload
      }
    })

    // Map to expected format
    const mappedVersions = versions.map(v => ({
      id: v.versionId,
      timestamp: v.timestamp.toISOString(),
      author: v.author,
      changeCount: v.changeCount,
      description: v.description
    }))

    return NextResponse.json(mappedVersions)
  } catch (error) {
    console.error('Error reading versions:', error)
    return NextResponse.json({ error: 'Failed to fetch versions' }, { status: 500 })
  }
}
GET function · typescript · L9-L25 (17 LOC)
src/app/api/employees/[id]/route.ts
export async function GET(
  request: NextRequest,
  context: RouteContext
) {
  try {
    const params = await context.params
    const employee = await getEmployeeById(params.id)

    if (!employee) {
      return NextResponse.json({ error: 'Employee not found' }, { status: 404 })
    }

    return NextResponse.json(employee)
  } catch (error) {
    return NextResponse.json({ error: 'Failed to fetch employee' }, { status: 500 })
  }
}
PATCH function · typescript · L27-L49 (23 LOC)
src/app/api/employees/[id]/route.ts
export async function PATCH(
  request: NextRequest,
  context: RouteContext
) {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const params = await context.params
    const body = await request.json()
    const employee = await updateEmployee(params.id, body)

    if (!employee) {
      return NextResponse.json({ error: 'Employee not found' }, { status: 404 })
    }

    return NextResponse.json(employee)
  } catch (error) {
    return NextResponse.json({ error: 'Failed to update employee' }, { status: 500 })
  }
}
DELETE function · typescript · L51-L72 (22 LOC)
src/app/api/employees/[id]/route.ts
export async function DELETE(
  request: NextRequest,
  context: RouteContext
) {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const params = await context.params
    const success = await deleteEmployee(params.id)

    if (!success) {
      return NextResponse.json({ error: 'Employee not found' }, { status: 404 })
    }

    return NextResponse.json({ success: true })
  } catch (error) {
    return NextResponse.json({ error: 'Failed to delete employee' }, { status: 500 })
  }
}
GET function · typescript · L5-L12 (8 LOC)
src/app/api/employees/route.ts
export async function GET() {
  try {
    const employees = await getAllEmployees()
    return NextResponse.json(employees)
  } catch (error) {
    return NextResponse.json({ error: 'Failed to fetch employees' }, { status: 500 })
  }
}
Repobility — the code-quality scanner for AI-generated software · https://repobility.com
POST function · typescript · L14-L28 (15 LOC)
src/app/api/employees/route.ts
export async function POST(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const body = await request.json()
    const newEmployee = await addEmployee(body)

    return NextResponse.json(newEmployee, { status: 201 })
  } catch (error) {
    return NextResponse.json({ error: 'Failed to create employee' }, { status: 500 })
  }
}
PUT function · typescript · L30-L44 (15 LOC)
src/app/api/employees/route.ts
export async function PUT(request: NextRequest) {
  try {
    const user = await getSessionFromCookie()
    if (!user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const employees = await request.json()
    await saveEmployees(employees)

    return NextResponse.json({ success: true })
  } catch (error) {
    return NextResponse.json({ error: 'Failed to update employees' }, { status: 500 })
  }
}
GET function · typescript · L9-L32 (24 LOC)
src/app/api/internal/allowed-ips/route.ts
export async function GET(request: NextRequest) {
  const authHeader = request.headers.get('x-internal-secret')
  const internalSecret = process.env.INTERNAL_API_SECRET

  if (!internalSecret || authHeader !== internalSecret) {
    return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
  }

  try {
    const allowedIPs = await prisma.allowedIP.findMany({
      select: { ip: true },
    })

    const ips = allowedIPs.map((record) => record.ip)

    return NextResponse.json({ ips })
  } catch (error) {
    console.error('Failed to fetch allowed IPs:', error)
    return NextResponse.json(
      { error: 'Failed to fetch allowed IPs' },
      { status: 500 }
    )
  }
}
page 1 / 3next ›