{"version":3,"file":"authz-CN4dwR0M.mjs","names":[],"sources":["../src/database/repositories/authz.ts"],"sourcesContent":["/**\n * Roles and policies.\n *\n * Read side feeds the per-request resolver; write side backs the admin API.\n * Built-in rows are protected: they cannot be deleted, their slug and\n * built-in flag are immutable, and a built-in policy's rules are frozen —\n * they document what the fixed level always did. Narrow a built-in role by\n * attaching a policy with a `deny`, not by rewriting its tier policy.\n */\n\nimport {\n\tisBuiltinPolicySlug,\n\tisBuiltinRoleSlug,\n\tvalidatePolicyRules,\n\tPermissions,\n\ttype PolicyLike,\n\ttype PolicyRules,\n} from \"@premium-cms/auth\";\nimport type { Kysely, Updateable } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport type { Database, PolicyTable, RoleTable } from \"../types.js\";\n\nfunction parseJsonColumn<T>(raw: string | null): T | null {\n\tif (!raw) return null;\n\ttry {\n\t\treturn JSON.parse(raw) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport interface RoleRecord {\n\tid: string;\n\tslug: string;\n\tname: string;\n\tdescription: string | null;\n\tlevel: number;\n\tbuiltin: boolean;\n\tpolicies: string[]; // slugs, in sort order\n\tuserCount: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface PolicyRecord {\n\tid: string;\n\tslug: string;\n\tname: string;\n\tdescription: string | null;\n\tbuiltin: boolean;\n\trules: PolicyRules;\n\troles: string[]; // slugs of roles holding it\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface RoleInput {\n\tslug: string;\n\tname: string;\n\tdescription?: string | null;\n\tlevel?: number;\n\tpolicies?: string[]; // slugs\n}\n\nexport interface PolicyInput {\n\tslug: string;\n\tname: string;\n\tdescription?: string | null;\n\trules: PolicyRules;\n}\n\nexport class AuthzError extends Error {\n\tconstructor(\n\t\tpublic code:\n\t\t\t| \"NOT_FOUND\"\n\t\t\t| \"SLUG_TAKEN\"\n\t\t\t| \"BUILTIN_IMMUTABLE\"\n\t\t\t| \"ROLE_IN_USE\"\n\t\t\t| \"POLICY_IN_USE\"\n\t\t\t| \"INVALID_RULES\"\n\t\t\t| \"UNKNOWN_POLICY\"\n\t\t\t| \"INVALID_SLUG\"\n\t\t\t| \"INVALID_LEVEL\",\n\t\tmessage: string,\n\t\tpublic details?: Record<string, unknown>,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"AuthzError\";\n\t}\n}\n\nconst SLUG_RE = /^[a-z][a-z0-9-]{1,63}$/;\nconst VALID_LEVELS = new Set([10, 20, 30, 40, 50]);\nconst KNOWN_PERMISSIONS: ReadonlySet<string> = new Set(Object.keys(Permissions));\n\nfunction assertSlug(slug: string): void {\n\tif (!SLUG_RE.test(slug)) {\n\t\tthrow new AuthzError(\n\t\t\t\"INVALID_SLUG\",\n\t\t\t\"Slug must be 2–64 characters of lowercase letters, digits and hyphens, starting with a letter\",\n\t\t);\n\t}\n}\n\nfunction parseRules(raw: string): PolicyRules {\n\treturn parseJsonColumn<PolicyRules>(raw) ?? {};\n}\n\nexport class AuthzRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t// ── Roles ────────────────────────────────────────────────────────\n\n\tasync listRoles(): Promise<RoleRecord[]> {\n\t\tconst roles = await this.db\n\t\t\t.selectFrom(\"_emdash_roles\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"level\", \"desc\")\n\t\t\t.orderBy(\"name\")\n\t\t\t.execute();\n\t\tif (roles.length === 0) return [];\n\n\t\tconst links = await this.db\n\t\t\t.selectFrom(\"_emdash_role_policies\")\n\t\t\t.innerJoin(\"_emdash_policies\", \"_emdash_policies.id\", \"_emdash_role_policies.policy_id\")\n\t\t\t.select([\n\t\t\t\t\"_emdash_role_policies.role_id\",\n\t\t\t\t\"_emdash_policies.slug\",\n\t\t\t\t\"_emdash_role_policies.sort_order\",\n\t\t\t])\n\t\t\t.orderBy(\"_emdash_role_policies.sort_order\")\n\t\t\t.execute();\n\n\t\tconst counts = await this.db\n\t\t\t.selectFrom(\"users\")\n\t\t\t.select([\"role_id\", (eb) => eb.fn.count<number>(\"id\").as(\"n\")])\n\t\t\t.where(\"role_id\", \"is not\", null)\n\t\t\t.groupBy(\"role_id\")\n\t\t\t.execute();\n\n\t\tconst policiesByRole = new Map<string, string[]>();\n\t\tfor (const l of links) {\n\t\t\tconst arr = policiesByRole.get(l.role_id) ?? [];\n\t\t\tarr.push(l.slug);\n\t\t\tpoliciesByRole.set(l.role_id, arr);\n\t\t}\n\t\tconst countByRole = new Map(counts.map((c) => [c.role_id as string, Number(c.n)]));\n\n\t\treturn roles.map((r) => ({\n\t\t\tid: r.id,\n\t\t\tslug: r.slug,\n\t\t\tname: r.name,\n\t\t\tdescription: r.description,\n\t\t\tlevel: r.level,\n\t\t\tbuiltin: r.builtin === 1,\n\t\t\tpolicies: policiesByRole.get(r.id) ?? [],\n\t\t\tuserCount: countByRole.get(r.id) ?? 0,\n\t\t\tcreatedAt: r.created_at,\n\t\t\tupdatedAt: r.updated_at,\n\t\t}));\n\t}\n\n\tasync getRole(idOrSlug: string): Promise<RoleRecord | null> {\n\t\tconst all = await this.listRoles();\n\t\treturn all.find((r) => r.id === idOrSlug || r.slug === idOrSlug) ?? null;\n\t}\n\n\tasync createRole(input: RoleInput): Promise<RoleRecord> {\n\t\tassertSlug(input.slug);\n\t\tif (isBuiltinRoleSlug(input.slug)) {\n\t\t\tthrow new AuthzError(\"SLUG_TAKEN\", `\"${input.slug}\" is a built-in role`);\n\t\t}\n\t\tconst level = input.level ?? 10;\n\t\tif (!VALID_LEVELS.has(level))\n\t\t\tthrow new AuthzError(\"INVALID_LEVEL\", \"Level must be 10, 20, 30, 40 or 50\");\n\n\t\tconst existing = await this.db\n\t\t\t.selectFrom(\"_emdash_roles\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"slug\", \"=\", input.slug)\n\t\t\t.executeTakeFirst();\n\t\tif (existing)\n\t\t\tthrow new AuthzError(\"SLUG_TAKEN\", `A role with slug \"${input.slug}\" already exists`);\n\n\t\tconst policyIds = await this.resolvePolicyIds(input.policies ?? []);\n\t\tconst id = ulid();\n\t\tconst now = new Date().toISOString();\n\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_roles\")\n\t\t\t.values({\n\t\t\t\tid,\n\t\t\t\tslug: input.slug,\n\t\t\t\tname: input.name,\n\t\t\t\tdescription: input.description ?? null,\n\t\t\t\tlevel,\n\t\t\t\tbuiltin: 0,\n\t\t\t\tcreated_at: now,\n\t\t\t\tupdated_at: now,\n\t\t\t})\n\t\t\t.execute();\n\t\tawait this.setRolePolicies(id, policyIds);\n\n\t\treturn (await this.getRole(id))!;\n\t}\n\n\tasync updateRole(\n\t\tidOrSlug: string,\n\t\tinput: Partial<Omit<RoleInput, \"slug\">> & { slug?: string },\n\t): Promise<RoleRecord> {\n\t\tconst role = await this.getRole(idOrSlug);\n\t\tif (!role) throw new AuthzError(\"NOT_FOUND\", \"Role not found\");\n\n\t\tif (input.slug !== undefined && input.slug !== role.slug) {\n\t\t\tif (role.builtin)\n\t\t\t\tthrow new AuthzError(\"BUILTIN_IMMUTABLE\", \"A built-in role's slug cannot change\");\n\t\t\tassertSlug(input.slug);\n\t\t\tif (isBuiltinRoleSlug(input.slug))\n\t\t\t\tthrow new AuthzError(\"SLUG_TAKEN\", `\"${input.slug}\" is a built-in role`);\n\t\t\tconst taken = await this.db\n\t\t\t\t.selectFrom(\"_emdash_roles\")\n\t\t\t\t.select(\"id\")\n\t\t\t\t.where(\"slug\", \"=\", input.slug)\n\t\t\t\t.executeTakeFirst();\n\t\t\tif (taken)\n\t\t\t\tthrow new AuthzError(\"SLUG_TAKEN\", `A role with slug \"${input.slug}\" already exists`);\n\t\t}\n\t\tif (input.level !== undefined) {\n\t\t\tif (role.builtin && input.level !== role.level) {\n\t\t\t\tthrow new AuthzError(\"BUILTIN_IMMUTABLE\", \"A built-in role's level cannot change\");\n\t\t\t}\n\t\t\tif (!VALID_LEVELS.has(input.level))\n\t\t\t\tthrow new AuthzError(\"INVALID_LEVEL\", \"Level must be 10, 20, 30, 40 or 50\");\n\t\t}\n\n\t\tconst updates: Updateable<RoleTable> = { updated_at: new Date().toISOString() };\n\t\tif (input.name !== undefined) updates.name = input.name;\n\t\tif (input.description !== undefined) updates.description = input.description;\n\t\tif (input.slug !== undefined) updates.slug = input.slug;\n\t\tif (input.level !== undefined) updates.level = input.level;\n\t\tawait this.db.updateTable(\"_emdash_roles\").set(updates).where(\"id\", \"=\", role.id).execute();\n\n\t\tif (input.policies !== undefined) {\n\t\t\tconst ids = await this.resolvePolicyIds(input.policies);\n\t\t\tawait this.setRolePolicies(role.id, ids);\n\t\t}\n\n\t\t// Keep the legacy level column on users in step with the role, so\n\t\t// code paths without resolved grants keep a sensible floor.\n\t\tif (input.level !== undefined && input.level !== role.level) {\n\t\t\tawait this.db\n\t\t\t\t.updateTable(\"users\")\n\t\t\t\t.set({ role: input.level })\n\t\t\t\t.where(\"role_id\", \"=\", role.id)\n\t\t\t\t.execute();\n\t\t}\n\n\t\treturn (await this.getRole(role.id))!;\n\t}\n\n\tasync deleteRole(idOrSlug: string): Promise<void> {\n\t\tconst role = await this.getRole(idOrSlug);\n\t\tif (!role) throw new AuthzError(\"NOT_FOUND\", \"Role not found\");\n\t\tif (role.builtin) throw new AuthzError(\"BUILTIN_IMMUTABLE\", \"Built-in roles cannot be deleted\");\n\t\tif (role.userCount > 0) {\n\t\t\tthrow new AuthzError(\"ROLE_IN_USE\", `${role.userCount} user(s) still hold this role`, {\n\t\t\t\tuserCount: role.userCount,\n\t\t\t});\n\t\t}\n\t\tawait this.db.deleteFrom(\"_emdash_role_policies\").where(\"role_id\", \"=\", role.id).execute();\n\t\tawait this.db.deleteFrom(\"_emdash_roles\").where(\"id\", \"=\", role.id).execute();\n\t}\n\n\tprivate async setRolePolicies(roleId: string, policyIds: string[]): Promise<void> {\n\t\tawait this.db.deleteFrom(\"_emdash_role_policies\").where(\"role_id\", \"=\", roleId).execute();\n\t\tif (policyIds.length === 0) return;\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_role_policies\")\n\t\t\t.values(\n\t\t\t\tpolicyIds.map((policy_id, sort_order) => ({ role_id: roleId, policy_id, sort_order })),\n\t\t\t)\n\t\t\t.execute();\n\t}\n\n\tprivate async resolvePolicyIds(slugs: string[]): Promise<string[]> {\n\t\tconst unique = [...new Set(slugs)];\n\t\tif (unique.length === 0) return [];\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_policies\")\n\t\t\t.select([\"id\", \"slug\"])\n\t\t\t.where(\"slug\", \"in\", unique)\n\t\t\t.execute();\n\t\tconst bySlug = new Map(rows.map((r) => [r.slug, r.id]));\n\t\tconst missing = unique.filter((s) => !bySlug.has(s));\n\t\tif (missing.length > 0) {\n\t\t\tthrow new AuthzError(\"UNKNOWN_POLICY\", `Unknown policy: ${missing.join(\", \")}`, { missing });\n\t\t}\n\t\treturn unique.map((s) => bySlug.get(s)!);\n\t}\n\n\t// ── Policies ─────────────────────────────────────────────────────\n\n\tasync listPolicies(): Promise<PolicyRecord[]> {\n\t\tconst policies = await this.db\n\t\t\t.selectFrom(\"_emdash_policies\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"builtin\", \"desc\")\n\t\t\t.orderBy(\"name\")\n\t\t\t.execute();\n\t\tif (policies.length === 0) return [];\n\n\t\tconst links = await this.db\n\t\t\t.selectFrom(\"_emdash_role_policies\")\n\t\t\t.innerJoin(\"_emdash_roles\", \"_emdash_roles.id\", \"_emdash_role_policies.role_id\")\n\t\t\t.select([\"_emdash_role_policies.policy_id\", \"_emdash_roles.slug\"])\n\t\t\t.execute();\n\t\tconst rolesByPolicy = new Map<string, string[]>();\n\t\tfor (const l of links) {\n\t\t\tconst arr = rolesByPolicy.get(l.policy_id) ?? [];\n\t\t\tarr.push(l.slug);\n\t\t\trolesByPolicy.set(l.policy_id, arr);\n\t\t}\n\n\t\treturn policies.map((p) => ({\n\t\t\tid: p.id,\n\t\t\tslug: p.slug,\n\t\t\tname: p.name,\n\t\t\tdescription: p.description,\n\t\t\tbuiltin: p.builtin === 1,\n\t\t\trules: parseRules(p.rules),\n\t\t\troles: rolesByPolicy.get(p.id) ?? [],\n\t\t\tcreatedAt: p.created_at,\n\t\t\tupdatedAt: p.updated_at,\n\t\t}));\n\t}\n\n\tasync getPolicy(idOrSlug: string): Promise<PolicyRecord | null> {\n\t\tconst all = await this.listPolicies();\n\t\treturn all.find((p) => p.id === idOrSlug || p.slug === idOrSlug) ?? null;\n\t}\n\n\tasync createPolicy(input: PolicyInput): Promise<PolicyRecord> {\n\t\tassertSlug(input.slug);\n\t\tif (isBuiltinPolicySlug(input.slug))\n\t\t\tthrow new AuthzError(\"SLUG_TAKEN\", `\"${input.slug}\" is a built-in policy`);\n\t\tconst validation = validatePolicyRules(input.rules, KNOWN_PERMISSIONS);\n\t\tif (!validation.valid) {\n\t\t\tthrow new AuthzError(\"INVALID_RULES\", validation.errors.join(\"; \"), {\n\t\t\t\terrors: validation.errors,\n\t\t\t});\n\t\t}\n\t\tconst existing = await this.db\n\t\t\t.selectFrom(\"_emdash_policies\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"slug\", \"=\", input.slug)\n\t\t\t.executeTakeFirst();\n\t\tif (existing)\n\t\t\tthrow new AuthzError(\"SLUG_TAKEN\", `A policy with slug \"${input.slug}\" already exists`);\n\n\t\tconst id = ulid();\n\t\tconst now = new Date().toISOString();\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_policies\")\n\t\t\t.values({\n\t\t\t\tid,\n\t\t\t\tslug: input.slug,\n\t\t\t\tname: input.name,\n\t\t\t\tdescription: input.description ?? null,\n\t\t\t\tbuiltin: 0,\n\t\t\t\trules: JSON.stringify(input.rules),\n\t\t\t\tcreated_at: now,\n\t\t\t\tupdated_at: now,\n\t\t\t})\n\t\t\t.execute();\n\t\treturn (await this.getPolicy(id))!;\n\t}\n\n\tasync updatePolicy(\n\t\tidOrSlug: string,\n\t\tinput: Partial<Omit<PolicyInput, \"slug\">> & { slug?: string },\n\t): Promise<PolicyRecord> {\n\t\tconst policy = await this.getPolicy(idOrSlug);\n\t\tif (!policy) throw new AuthzError(\"NOT_FOUND\", \"Policy not found\");\n\n\t\tif (input.slug !== undefined && input.slug !== policy.slug) {\n\t\t\tif (policy.builtin)\n\t\t\t\tthrow new AuthzError(\"BUILTIN_IMMUTABLE\", \"A built-in policy's slug cannot change\");\n\t\t\tassertSlug(input.slug);\n\t\t\tif (isBuiltinPolicySlug(input.slug))\n\t\t\t\tthrow new AuthzError(\"SLUG_TAKEN\", `\"${input.slug}\" is a built-in policy`);\n\t\t\tconst taken = await this.db\n\t\t\t\t.selectFrom(\"_emdash_policies\")\n\t\t\t\t.select(\"id\")\n\t\t\t\t.where(\"slug\", \"=\", input.slug)\n\t\t\t\t.executeTakeFirst();\n\t\t\tif (taken)\n\t\t\t\tthrow new AuthzError(\"SLUG_TAKEN\", `A policy with slug \"${input.slug}\" already exists`);\n\t\t}\n\t\tif (input.rules !== undefined) {\n\t\t\tif (policy.builtin) {\n\t\t\t\tthrow new AuthzError(\n\t\t\t\t\t\"BUILTIN_IMMUTABLE\",\n\t\t\t\t\t\"A built-in policy's rules are fixed. Attach an extra policy to the role instead — a deny in it overrides this one.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst validation = validatePolicyRules(input.rules, KNOWN_PERMISSIONS);\n\t\t\tif (!validation.valid) {\n\t\t\t\tthrow new AuthzError(\"INVALID_RULES\", validation.errors.join(\"; \"), {\n\t\t\t\t\terrors: validation.errors,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst updates: Updateable<PolicyTable> = { updated_at: new Date().toISOString() };\n\t\tif (input.name !== undefined) updates.name = input.name;\n\t\tif (input.description !== undefined) updates.description = input.description;\n\t\tif (input.slug !== undefined) updates.slug = input.slug;\n\t\tif (input.rules !== undefined) updates.rules = JSON.stringify(input.rules);\n\t\tawait this.db\n\t\t\t.updateTable(\"_emdash_policies\")\n\t\t\t.set(updates)\n\t\t\t.where(\"id\", \"=\", policy.id)\n\t\t\t.execute();\n\t\treturn (await this.getPolicy(policy.id))!;\n\t}\n\n\tasync deletePolicy(idOrSlug: string): Promise<void> {\n\t\tconst policy = await this.getPolicy(idOrSlug);\n\t\tif (!policy) throw new AuthzError(\"NOT_FOUND\", \"Policy not found\");\n\t\tif (policy.builtin)\n\t\t\tthrow new AuthzError(\"BUILTIN_IMMUTABLE\", \"Built-in policies cannot be deleted\");\n\t\tif (policy.roles.length > 0) {\n\t\t\tthrow new AuthzError(\"POLICY_IN_USE\", `Held by role(s): ${policy.roles.join(\", \")}`, {\n\t\t\t\troles: policy.roles,\n\t\t\t});\n\t\t}\n\t\tawait this.db.deleteFrom(\"_emdash_policies\").where(\"id\", \"=\", policy.id).execute();\n\t}\n\n\t// ── Resolution inputs ────────────────────────────────────────────\n\n\t/** The policies a role holds, in sort order — the resolver's input. */\n\tasync policiesForRole(roleId: string): Promise<PolicyLike[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_role_policies\")\n\t\t\t.innerJoin(\"_emdash_policies\", \"_emdash_policies.id\", \"_emdash_role_policies.policy_id\")\n\t\t\t.select([\"_emdash_policies.slug\", \"_emdash_policies.rules\"])\n\t\t\t.where(\"_emdash_role_policies.role_id\", \"=\", roleId)\n\t\t\t.orderBy(\"_emdash_role_policies.sort_order\")\n\t\t\t.execute();\n\t\treturn rows.map((r) => ({ slug: r.slug, rules: parseRules(r.rules) }));\n\t}\n\n\t/** Policies by slug, in the order given; unknown slugs are dropped. */\n\tasync policiesBySlugs(slugs: readonly string[]): Promise<PolicyLike[]> {\n\t\tif (slugs.length === 0) return [];\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_policies\")\n\t\t\t.select([\"slug\", \"rules\"])\n\t\t\t.where(\"slug\", \"in\", [...slugs])\n\t\t\t.execute();\n\t\tconst bySlug = new Map(rows.map((r) => [r.slug, parseRules(r.rules)]));\n\t\treturn slugs.filter((s) => bySlug.has(s)).map((s) => ({ slug: s, rules: bySlug.get(s)! }));\n\t}\n\n\tasync roleSummary(\n\t\troleId: string,\n\t): Promise<{ id: string; slug: string; name: string; level: number; builtin: boolean } | null> {\n\t\tconst r = await this.db\n\t\t\t.selectFrom(\"_emdash_roles\")\n\t\t\t.select([\"id\", \"slug\", \"name\", \"level\", \"builtin\"])\n\t\t\t.where(\"id\", \"=\", roleId)\n\t\t\t.executeTakeFirst();\n\t\treturn r\n\t\t\t? { id: r.id, slug: r.slug, name: r.name, level: r.level, builtin: r.builtin === 1 }\n\t\t\t: null;\n\t}\n\n\tasync roleIdForSlug(slug: string): Promise<string | null> {\n\t\tconst r = await this.db\n\t\t\t.selectFrom(\"_emdash_roles\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"slug\", \"=\", slug)\n\t\t\t.executeTakeFirst();\n\t\treturn r?.id ?? null;\n\t}\n}\n"],"mappings":"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"}