import path from 'path'; const COURSEWARE_ID_PATTERN = /^[a-zA-Z0-9_-]+$/; export function isValidCoursewareId(value: unknown): value is string { return typeof value === 'string' && COURSEWARE_ID_PATTERN.test(value); } export function assertCoursewareId(value: unknown): asserts value is string { if (!isValidCoursewareId(value)) { throw new Error('Invalid coursewareId'); } } export function isValidCoursewareVersion(value: unknown): value is number { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 1; } export function assertCoursewareVersion(value: unknown): asserts value is number { if (!isValidCoursewareVersion(value)) { throw new Error('Invalid courseware version'); } } /** Resolve exactly one direct child without allowing absolute paths or traversal. */ export function resolveDirectChildPath(rootDir: string, childName: string): string { if (!childName || path.basename(childName) !== childName) { throw new Error('Invalid courseware storage path'); } const root = path.resolve(rootDir); const child = path.resolve(root, childName); if (path.dirname(child) !== root) { throw new Error('Invalid courseware storage path'); } return child; }