1import { schema as s } from "jazz-tools";2import type { BooleanColumn, DefinedTable, RefColumn, StringColumn } from "jazz-tools";34function requireTableName(name: string, helper: string): void {5 if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(name)) {6 throw new TypeError(7 `${helper} requires a declared Jazz table name, received ${JSON.stringify(name)}`,8 );9 }10}1112/** Creates the conventional relationship table used by `sharedAccess`. */13export function sharedGrantTable<const Resource extends string>(14 resource: Resource,15): DefinedTable<{16 resourceId: RefColumn<Resource>;17 user_id: StringColumn;18 can_edit: BooleanColumn;19}> {20 requireTableName(resource, "sharedGrantTable");21 return s.table({22 resourceId: s.ref(resource),23 user_id: s.string(),24 can_edit: s.boolean(),25 });26}2728/** Fixed Wave 2 group roles. Custom role systems remain a raw Jazz escape hatch. */29export const groupRoles = ["reader", "contributor", "writer", "admin"] as const;30/** Fixed group roles supported by the built-in group policy template. */31export type GroupRole = (typeof groupRoles)[number];3233/** Returns the persisted capability flags for a fixed group role. */34export function groupRoleCapabilities(role: GroupRole): {35 readonly role: GroupRole;36 readonly can_create: boolean;37 readonly can_edit_any: boolean;38 readonly can_manage: boolean;39} {40 return {41 role,42 can_create: role !== "reader",43 can_edit_any: role === "writer" || role === "admin",44 can_manage: role === "admin",45 } as const;46}4748/** Creates the conventional relationship table used by `groupAccess`. */49export function groupMembershipTable<const Group extends string>(50 group: Group,51): DefinedTable<{52 groupId: RefColumn<Group>;53 user_id: StringColumn;54 role: StringColumn;55 can_create: BooleanColumn;56 can_edit_any: BooleanColumn;57 can_manage: BooleanColumn;58}> {59 requireTableName(group, "groupMembershipTable");60 return s.table({61 groupId: s.ref(group),62 user_id: s.string(),63 role: s.string(),64 can_create: s.boolean(),65 can_edit_any: s.boolean(),66 can_manage: s.boolean(),67 });68}