Browse Source
- Create API route structure (auth, health, internal) - Add authentication middleware for internal pages - Add database connection utilities - Implement health check endpointmain
2 changed files with 87 additions and 0 deletions
@ -0,0 +1,53 @@ |
|||||
|
/** |
||||
|
* Basic Authentication Middleware for /internal/* routes |
||||
|
* Protects internal pages (styleguide, admin tools) with HTTP Basic Auth |
||||
|
*/ |
||||
|
|
||||
|
export default defineEventHandler((event) => { |
||||
|
const path = event.path |
||||
|
|
||||
|
// Only protect /internal/* routes
|
||||
|
if (!path.startsWith('/internal')) { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
const config = useRuntimeConfig() |
||||
|
|
||||
|
// Get credentials from environment variables
|
||||
|
const validUsername = config.internalAuthUsername |
||||
|
const validPassword = config.internalAuthPassword |
||||
|
|
||||
|
// Skip auth if credentials are not configured (development convenience)
|
||||
|
if (!validUsername || !validPassword) { |
||||
|
console.warn('⚠️ INTERNAL_AUTH_USERNAME or INTERNAL_AUTH_PASSWORD not set. /internal routes are unprotected!') |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// Get Authorization header
|
||||
|
const authHeader = getHeader(event, 'authorization') |
||||
|
|
||||
|
if (!authHeader || !authHeader.startsWith('Basic ')) { |
||||
|
// Request authentication
|
||||
|
setHeader(event, 'WWW-Authenticate', 'Basic realm="Internal Area"') |
||||
|
throw createError({ |
||||
|
statusCode: 401, |
||||
|
statusMessage: 'Authentication required', |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// Decode credentials
|
||||
|
const base64Credentials = authHeader.split(' ')[1] |
||||
|
const credentials = Buffer.from(base64Credentials, 'base64').toString('utf-8') |
||||
|
const [username, password] = credentials.split(':') |
||||
|
|
||||
|
// Validate credentials
|
||||
|
if (username !== validUsername || password !== validPassword) { |
||||
|
setHeader(event, 'WWW-Authenticate', 'Basic realm="Internal Area"') |
||||
|
throw createError({ |
||||
|
statusCode: 401, |
||||
|
statusMessage: 'Invalid credentials', |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// Authentication successful, continue
|
||||
|
}) |
||||
@ -0,0 +1,34 @@ |
|||||
|
import { drizzle } from 'drizzle-orm/postgres-js' |
||||
|
import postgres from 'postgres' |
||||
|
import * as schema from '../database/schema' |
||||
|
|
||||
|
/** |
||||
|
* Database connection utility |
||||
|
* |
||||
|
* Creates a singleton Drizzle ORM instance with the complete schema. |
||||
|
* This allows for type-safe database queries throughout the application. |
||||
|
* |
||||
|
* Usage: |
||||
|
* ```typescript
|
||||
|
* import { db } from '~/server/utils/db' |
||||
|
* |
||||
|
* // Query with relations
|
||||
|
* const users = await db.query.users.findMany({ |
||||
|
* with: { orders: true } |
||||
|
* }) |
||||
|
* |
||||
|
* // Raw SQL with type safety
|
||||
|
* import { users } from '~/server/database/schema' |
||||
|
* import { eq } from 'drizzle-orm' |
||||
|
* |
||||
|
* const user = await db.select().from(users).where(eq(users.id, userId)) |
||||
|
* ``` |
||||
|
*/ |
||||
|
|
||||
|
const config = useRuntimeConfig() |
||||
|
|
||||
|
// Create postgres.js client
|
||||
|
const client = postgres(config.databaseUrl) |
||||
|
|
||||
|
// Create Drizzle ORM instance with schema
|
||||
|
export const db = drizzle(client, { schema }) |
||||
Loading…
Reference in new issue