v3: shared/ is documented like api/ — deno doc --lint over api/ and shared/ goes from 385 errors to none — every module of shared/ opens with a /** … @module */ block; every export and every field of an exported interface has JSDoc, each request body naming the endpoint that takes it and each response its endpoint; the // comments that described declarations (the mention pattern, the permission union and table, four socket messages, the error message's optimistic-action context) are /** */ now, and the socket protocol's heading comment, which sat on no declaration, is its module doc. The lint wanted explicit types on MENTION_RE and DUMP_MAX_FILE_SIZE_BYTES. Along the way: the chat edit is allowed to moderators too, which the new ChatEditMessage doc says; UpdateUserRequest says that PATCH /api/users/me takes only its description and email; playlist-service's reorderPlaylist @throws is rewrapped. mod.ts and the README no longer call shared/ undocumented. No behaviour changes; 205 backend tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
khannurien
2026-09-27 21:13:07 +00:00
parent d62e4a9883
commit b85a71d86e
18 changed files with 599 additions and 59 deletions

View File

@@ -1,7 +1,16 @@
/**
* The role permissions, one table for the server that enforces them and the
* client that hides what a role can't do.
*
* @module
*/
import type { Role } from "./user.ts";
// Named capabilities checked at enforcement points. Extend this union as new
// gated capabilities are added (e.g. "invite:manage").
/**
* Named capabilities checked at enforcement points. Extend this union as new
* gated capabilities are added (e.g. "invite:manage").
*/
export type Permission =
| "dump:moderate"
| "comment:moderate"
@@ -10,6 +19,7 @@ export type Permission =
| "user:manage"
| "category:manage";
/** Every {@link Permission}. */
const ALL_PERMISSIONS: readonly Permission[] = [
"dump:moderate",
"comment:moderate",
@@ -19,8 +29,11 @@ const ALL_PERMISSIONS: readonly Permission[] = [
"category:manage",
];
// Roles are fixed in code. `admin` is a superset of every permission (current
// and future); `moderator` gets the content-moderation permissions only.
/**
* What each role may do. Roles are fixed in code. `admin` is a superset of
* every permission (current and future); `moderator` gets the
* content-moderation permissions only.
*/
export const ROLE_PERMISSIONS: Record<Role, readonly Permission[]> = {
admin: ALL_PERMISSIONS,
moderator: [
@@ -32,6 +45,7 @@ export const ROLE_PERMISSIONS: Record<Role, readonly Permission[]> = {
user: [],
};
/** Checks whether `role` grants `permission`. */
export function hasPermission(role: Role, permission: Permission): boolean {
return ROLE_PERMISSIONS[role].includes(permission);
}