feat(contracts): shared server, exercise, ai, import and web interfaces

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-10-30 02:48:10 +01:00
1 parent 9f582b99d2
commit 3b15d87a5f
7 files changed
+103

No files matched your search

+28
View File
@@ -0,0 +1,28 @@
export type Role = "owner" | "author" | "learner";
export interface AuthUser { id: string; email: string; name: string; roles: Role[]; groups: string[] }
export interface RequestContext { user: AuthUser | null; params: Record<string, string>; url: URL }
export type RouteHandler = (req: Request, rc: RequestContext) => Response | Promise<Response>;
export interface Feature {
name: string; // "learner" | "import" | "studio" | "ai" | "core"
routes: Record<string, Partial<Record<"GET"|"POST"|"PUT"|"PATCH"|"DELETE", RouteHandler>>>; // paths start with /api/
jobs?: Record<string, JobHandler>; // job kind -> handler
}
export interface JobContext { reportProgress(fraction: number, message?: string): Promise<void>; signal: AbortSignal }
export type JobHandler = (payload: unknown, jc: JobContext) => Promise<unknown>;
export type JobStatus = "queued" | "running" | "done" | "failed";
export interface JobRecord { id: string; kind: string; status: JobStatus; progress: number; message: string | null; payload: unknown; result: unknown; error: string | null; createdAt: string; updatedAt: string }
export interface JobQueue { enqueue(kind: string, payload: unknown): Promise<string>; get(id: string): Promise<JobRecord | null>; list(kind?: string): Promise<JobRecord[]> }
export interface AuthService { userFromRequest(req: Request): Promise<AuthUser | null> }
// Placeholders until Task 4 (@stc/db) and Task 7 (@stc/course-format) exist; switch to the real imports in Task 7.
type Db = unknown;
type CourseRepository = unknown;
export interface ServerContext {
config: AppConfig; db: Db; courses: CourseRepository;
jobs: JobQueue; auth: AuthService;
}
export interface AppConfig {
port: number; databaseUrl: string; dataDir: string; // dataDir holds cache/, media/, worktrees/
courseDirs: string[]; // folders scanned for stcourse.yaml (course repos and overlays/)
secret: string; // STC_SECRET, used to encrypt BYOK keys
publicUrl: string;
}