accounts/dashboard-fresh/api/content-utils.ts
Haitao Pan 9c877ceb3c feat(dashboard-fresh): migrate and integrate dashboard source
- Add fresh app structure (auth, tenant, mail, insight, docs, panel)
- Include CMS content, API routes, scripts, and config
- Migrate UI components, themes, and extensions to fresh runtime
2025-11-04 18:06:21 +08:00

59 lines
1.5 KiB
TypeScript

/**
* Content utilities for Fresh + Deno
*
* Provides path handling and validation for content files
*/
import { join, normalize, relative } from '$std/path/mod.ts'
export class ContentNotFoundError extends Error {
constructor(message: string) {
super(message)
this.name = 'ContentNotFoundError'
}
}
const CONTENT_ROOT = join(Deno.cwd(), 'content')
export function getContentRoot(): string {
return CONTENT_ROOT
}
export function normalizeContentPath(requestPath: string): string {
if (!requestPath) {
throw new Error('Missing content path')
}
const normalizedRequest = requestPath.replace(/\\/g, '/').replace(/^\/+/, '')
const resolvedPath = join(CONTENT_ROOT, normalizedRequest)
const normalizedAbsolute = normalize(resolvedPath)
if (!normalizedAbsolute.startsWith(CONTENT_ROOT)) {
throw new Error('Invalid content path')
}
return normalizedAbsolute
}
export async function assertContentFile(requestPath: string): Promise<string> {
const absolutePath = normalizeContentPath(requestPath)
try {
const stats = await Deno.stat(absolutePath)
if (!stats.isFile) {
throw new ContentNotFoundError(`Content file not found: ${requestPath}`)
}
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
throw new ContentNotFoundError(`Content file not found: ${requestPath}`)
}
throw error
}
return absolutePath
}
export function toContentRelativePath(absolutePath: string): string {
return relative(CONTENT_ROOT, absolutePath)
}