forked from EduCraft/curriculum-project-hub
feat(database): init database folder frontend and permission
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 文件库领域基础:角色秩、命名规则(D14)、错误类型。
|
||||
*
|
||||
* 语义锚定:仓库根《文件库-接口契约.md》(2.2 权限等级 / D8 可见性 / D14 命名)
|
||||
* 与 .omo/文件库-开工计划.md。本模块是独立文件库,不复用 hub 的
|
||||
* Folder/Project/PermissionGrant 体系。
|
||||
*/
|
||||
|
||||
export const FILE_LIB_ROLES = ["VIEW", "EDIT", "MANAGE"] as const;
|
||||
export type FileLibRole = (typeof FILE_LIB_ROLES)[number];
|
||||
|
||||
/** 契约 2.2:MANAGE > EDIT > VIEW,严格全序。 */
|
||||
export const ROLE_RANK: Record<FileLibRole, number> = { VIEW: 1, EDIT: 2, MANAGE: 3 };
|
||||
|
||||
export function roleAtLeast(role: FileLibRole, min: FileLibRole): boolean {
|
||||
return ROLE_RANK[role] >= ROLE_RANK[min];
|
||||
}
|
||||
|
||||
/** 业务错误。statusCode 由路由层映射为 HTTP 响应(D8 语义在此层只表达为 code)。 */
|
||||
export class FileLibError extends Error {
|
||||
constructor(
|
||||
readonly statusCode: number,
|
||||
readonly code: string,
|
||||
message: string,
|
||||
/** 结构化附加信息(如 409 时的 currentVersion),路由层并入错误响应。 */
|
||||
readonly details?: Record<string, unknown>,
|
||||
) {
|
||||
super(message);
|
||||
this.name = "FileLibError";
|
||||
}
|
||||
}
|
||||
|
||||
export const NODE_NAME_MAX_LENGTH = 128;
|
||||
|
||||
/** D14:禁 `/`;反斜杠同样禁止(它会变成存储路径的分隔符,且易用于伪装)。控制字符禁。 */
|
||||
const FORBIDDEN_NAME_CHARS = /[/\\\p{C}]/u;
|
||||
|
||||
/**
|
||||
* D14:NFC 归一化 + trim,然后校验长度与字符集。
|
||||
* 违规抛 FileLibError(400, "invalid_name"),路由层原样透传。
|
||||
*/
|
||||
export function normalizeNodeName(raw: string): string {
|
||||
const name = raw.normalize("NFC").trim();
|
||||
if (name.length === 0) {
|
||||
throw new FileLibError(400, "invalid_name", "name must not be empty");
|
||||
}
|
||||
if (name.length > NODE_NAME_MAX_LENGTH) {
|
||||
throw new FileLibError(400, "invalid_name", `name exceeds ${NODE_NAME_MAX_LENGTH} characters`);
|
||||
}
|
||||
if (FORBIDDEN_NAME_CHARS.test(name)) {
|
||||
throw new FileLibError(400, "invalid_name", "name must not contain '/', '\\' or control characters");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/** D14:活跃兄弟节点大小写不敏感唯一的比较键(DB 层另有部分唯一索引兜底)。 */
|
||||
export function nameKey(normalizedName: string): string {
|
||||
return normalizedName.toLowerCase();
|
||||
}
|
||||
Reference in New Issue
Block a user