feat: productionize learning engine and classroom
This commit is contained in:
1 parent
2d04197f3f
commit
ba35adfbfa
124 files changed
+9071
-796
No files matched your search
@@ -0,0 +1,34 @@
|
||||
import type { CourseRecord } from '@/lib/course-framework/types';
|
||||
import { readCourseRecord } from '@/lib/course-framework/store';
|
||||
import { readFrozenLearningPackageRecord } from '@/lib/makelore-course/package';
|
||||
|
||||
type CoursePublicationState = Pick<CourseRecord, 'publication' | 'externalPublication'>;
|
||||
|
||||
/** A frozen course id is a one-shot immutable product identity. */
|
||||
export class FrozenLearningCourseMutationError extends Error {
|
||||
constructor(public readonly courseId: string) {
|
||||
super(`课程 ${courseId} 已冻结,不能继续生成或重新生成;如需修改,请新建课程`);
|
||||
this.name = 'FrozenLearningCourseMutationError';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce the single immutable-course rule at every source mutation boundary.
|
||||
*
|
||||
* The frozen record is authoritative: Works can successfully finalize an
|
||||
* archive and then fail before writing the later external-publication receipt.
|
||||
* Legacy publication receipts remain additional evidence for courses created
|
||||
* before aggregate finalization was introduced.
|
||||
*/
|
||||
export async function assertLearningCourseMutable(
|
||||
courseId: string,
|
||||
knownRecord?: CoursePublicationState | null,
|
||||
): Promise<void> {
|
||||
const [frozen, record] = await Promise.all([
|
||||
readFrozenLearningPackageRecord(courseId),
|
||||
knownRecord === undefined ? readCourseRecord(courseId) : Promise.resolve(knownRecord),
|
||||
]);
|
||||
if (frozen || record?.publication || record?.externalPublication) {
|
||||
throw new FrozenLearningCourseMutationError(courseId);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user