export interface Org { id: string; name: string; parent_id: string | null; metadata: Record; } export interface Role { id: string | null; name: string; description: string | null; source: string; } export interface RoleDetail { id: string; org_id: string; org_name: string; name: string; description: string | null; } export interface Activity { name: string; description: string | null; } export interface View { name: string; description: string | null; } export interface Rule { id: string; role_id: string; org_id: string; org_name: string; role_name: string; activity: string; view: string; modality: 'permission' | 'prohibition'; priority: number | null; scope: string; } export interface CrossOrgRule { id: string; source_org_id: string; source_role_id: string; target_org_id: string; source_org_name: string; source_role_name: string; target_org_name: string; activity: string; view: string; modality: 'permission' | 'prohibition'; priority: number | null; } export interface UserRule { id: string; user_id: string; org_id: string; user_name: string; user_email: string | null; org_name: string; activity: string; view: string; modality: 'permission' | 'prohibition'; priority: number | null; } export interface GlobalRule { id: string; user_id: string | null; user_name: string | null; user_email: string | null; activity: string | null; view: string | null; modality: 'permission' | 'prohibition'; priority: number | null; is_system_principal: boolean; } export interface RoleHierarchy { senior_role_id: string; senior_name: string; junior_role_id: string; junior_name: string; org_id: string; org_name: string; } export interface SystemPrincipal { user_id: string; user_name: string; user_email: string | null; description: string | null; created_at: string; global_rules: { id: string; activity: string | null; view: string | null; modality: 'permission' | 'prohibition' }[]; } export interface UserDetail { id: string; email: string; name: string; account_type: 'user' | 'system' | 'service'; is_active: boolean; created_at: string; roles: { role_id: string; role_name: string; org_id: string; org_name: string }[]; } export interface RuleUser { id: string; user_name: string; email: string | null; account_type: 'user' | 'system' | 'service'; org_id: string; org_name: string; role_id: string | null; role_name: string | null; source: 'role' | 'direct'; } export interface EffectivePermission { activity: string | null; view: string | null; modality: 'permission' | 'prohibition'; scope: string | null; org_id: string | null; org_name: string | null; role_id: string | null; role_name: string | null; source: 'role' | 'direct' | 'global'; } export type ActivityViewBinding = { activity: string; view: string }; export interface MorbacApi { checkPermission(token: string, orgId: string, activity: string, view: string): Promise; getOrgs(token: string, orgIds: string[]): Promise; createOrg(token: string, orgIds: string[], data: { name: string; parent_id?: string }): Promise; updateOrg(token: string, orgIds: string[], id: string, data: { name?: string; parent_id?: string | null }): Promise; deleteOrg(token: string, orgIds: string[], id: string): Promise; getRoles(token: string, orgIds: string[]): Promise; createRole(token: string, orgIds: string[], data: { org_id: string; name: string; description?: string }): Promise; updateRole(token: string, orgIds: string[], id: string, data: { name?: string; description?: string }): Promise; deleteRole(token: string, orgIds: string[], id: string): Promise; getRoleHierarchy(token: string, orgIds: string[]): Promise; addRoleHierarchy(token: string, orgIds: string[], data: { senior_role_id: string; junior_role_id: string }): Promise; removeRoleHierarchy(token: string, orgIds: string[], data: { senior_role_id: string; junior_role_id: string }): Promise; getActivities(token: string, orgIds: string[]): Promise; getViews(token: string, orgIds: string[]): Promise; getActivityViewBindings(token: string, orgIds: string[]): Promise; getRules(token: string, orgIds: string[]): Promise; createRule(token: string, orgIds: string[], data: { org_id: string; role_id: string; activity: string; view: string; modality: 'permission' | 'prohibition'; scope?: string; priority?: number }): Promise; deleteRule(token: string, orgIds: string[], id: string): Promise; getCrossOrgRules(token: string, orgIds: string[]): Promise; createCrossOrgRule(token: string, orgIds: string[], data: { source_org_id: string; source_role_id: string; target_org_id: string; activity: string; view: string; modality: 'permission' | 'prohibition'; priority?: number }): Promise; deleteCrossOrgRule(token: string, orgIds: string[], id: string): Promise; getUserRules(token: string, orgIds: string[]): Promise; createUserRule(token: string, orgIds: string[], data: { user_id: string; org_id: string; activity: string; view: string; modality: 'permission' | 'prohibition'; priority?: number }): Promise; deleteUserRule(token: string, orgIds: string[], id: string): Promise; getGlobalRules(token: string, orgIds: string[]): Promise; createGlobalRule(token: string, orgIds: string[], data: { user_id?: string | null; activity?: string | null; view?: string | null; modality: 'permission' | 'prohibition'; priority?: number }): Promise; deleteGlobalRule(token: string, orgIds: string[], id: string): Promise; getSystemPrincipals(token: string, orgIds: string[]): Promise; getUsers(token: string, orgIds: string[]): Promise; createUser(token: string, orgIds: string[], data: { email: string; name: string; password: string }): Promise; updateUser(token: string, orgIds: string[], id: string, data: { name?: string; email?: string; is_active?: boolean; password?: string }): Promise; deleteUser(token: string, orgIds: string[], id: string): Promise; assignRole(token: string, orgIds: string[], data: { user_id: string; role_id: string; org_id: string }): Promise; removeRole(token: string, orgIds: string[], data: { user_id: string; role_id: string; org_id: string }): Promise; getActivityUsers(token: string, orgIds: string[], name: string): Promise; getViewUsers(token: string, orgIds: string[], name: string): Promise; getEffectivePermissions(token: string, orgIds: string[], userId: string): Promise; } export function createMorbacApi(apiUrl: string): MorbacApi { async function api(method: string, path: string, token: string, orgIds: string[], body?: unknown): Promise { const headers: Record = { Authorization: `Bearer ${token}`, }; if (orgIds.length === 1) { headers['X-Org-Id'] = orgIds[0]; } else if (orgIds.length > 1) { headers['X-Org-Ids'] = orgIds.join(','); } if (body !== undefined) headers['Content-Type'] = 'application/json'; const res = await fetch(`${apiUrl}${path}`, { method, headers, credentials: 'include', body: body !== undefined ? JSON.stringify(body) : undefined, }); if (res.status === 204) return null; const data = await res.json(); if (!res.ok) throw new Error((data as { error?: string }).error || 'Request failed'); return data; } return { checkPermission: async (token, orgId, activity, view) => { const res = await fetch(`${apiUrl}/me/permissions/check`, { method: 'POST', headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', 'X-Org-Id': orgId, }, credentials: 'include', body: JSON.stringify({ p_activity: activity, p_view: view }), }); if (!res.ok) return false; return res.json() as Promise; }, getOrgs: (t, orgIds) => api('GET', '/orgs', t, orgIds) as Promise, createOrg: (t, orgIds, d) => api('POST', '/orgs', t, orgIds, d) as Promise, updateOrg: (t, orgIds, id, d) => api('PATCH', `/orgs/${id}`, t, orgIds, d) as Promise, deleteOrg: (t, orgIds, id) => api('DELETE', `/orgs/${id}`, t, orgIds) as Promise, getRoles: (t, orgIds) => api('GET', '/roles', t, orgIds) as Promise, createRole: (t, orgIds, d) => api('POST', '/roles', t, orgIds, d) as Promise, updateRole: (t, orgIds, id, d) => api('PATCH', `/roles/${id}`, t, orgIds, d) as Promise, deleteRole: (t, orgIds, id) => api('DELETE', `/roles/${id}`, t, orgIds) as Promise, getRoleHierarchy: (t, orgIds) => api('GET', '/role-hierarchy', t, orgIds) as Promise, addRoleHierarchy: (t, orgIds, d) => api('POST', '/role-hierarchy', t, orgIds, d), removeRoleHierarchy: (t, orgIds, d) => api('DELETE', '/role-hierarchy', t, orgIds, d), getActivities: (t, orgIds) => api('GET', '/activities', t, orgIds) as Promise, getViews: (t, orgIds) => api('GET', '/views', t, orgIds) as Promise, getActivityViewBindings: (t, orgIds) => api('GET', '/activity-view-bindings', t, orgIds) as Promise, getRules: (t, orgIds) => api('GET', '/rules', t, orgIds) as Promise, createRule: (t, orgIds, d) => api('POST', '/rules', t, orgIds, d) as Promise, deleteRule: (t, orgIds, id) => api('DELETE', `/rules/${id}`, t, orgIds) as Promise, getCrossOrgRules: (t, orgIds) => api('GET', '/cross-org-rules', t, orgIds) as Promise, createCrossOrgRule: (t, orgIds, d) => api('POST', '/cross-org-rules', t, orgIds, d) as Promise, deleteCrossOrgRule: (t, orgIds, id) => api('DELETE', `/cross-org-rules/${id}`, t, orgIds) as Promise, getUserRules: (t, orgIds) => api('GET', '/user-rules', t, orgIds) as Promise, createUserRule: (t, orgIds, d) => api('POST', '/user-rules', t, orgIds, d) as Promise, deleteUserRule: (t, orgIds, id) => api('DELETE', `/user-rules/${id}`, t, orgIds) as Promise, getGlobalRules: (t, orgIds) => api('GET', '/global-rules', t, orgIds) as Promise, createGlobalRule: (t, orgIds, d) => api('POST', '/global-rules', t, orgIds, d) as Promise, deleteGlobalRule: (t, orgIds, id) => api('DELETE', `/global-rules/${id}`, t, orgIds) as Promise, getSystemPrincipals: (t, orgIds) => api('GET', '/system-principals', t, orgIds) as Promise, getUsers: (t, orgIds) => api('GET', '/users', t, orgIds) as Promise, createUser: (t, orgIds, d) => api('POST', '/users', t, orgIds, d) as Promise, updateUser: (t, orgIds, id, d) => api('PATCH', `/users/${id}`, t, orgIds, d) as Promise, deleteUser: (t, orgIds, id) => api('DELETE', `/users/${id}`, t, orgIds) as Promise, assignRole: (t, orgIds, d) => api('POST', `/users/${d.user_id}/roles`, t, orgIds, { role_id: d.role_id, org_id: d.org_id }), removeRole: (t, orgIds, d) => api('DELETE', `/users/${d.user_id}/roles`, t, orgIds, { role_id: d.role_id, org_id: d.org_id }), getActivityUsers: (t, orgIds, name) => api('GET', `/activities/${encodeURIComponent(name)}/users`, t, orgIds) as Promise, getViewUsers: (t, orgIds, name) => api('GET', `/views/${encodeURIComponent(name)}/users`, t, orgIds) as Promise, getEffectivePermissions: (t, orgIds, userId) => api('GET', `/users/${userId}/effective-permissions`, t, orgIds) as Promise, }; }