@fayz-ai/db 0.8.4 → 0.9.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,74 @@
1
+ -- ============================================================================
2
+ -- 021_tenant_roles.sql — custom access profiles, per tenant.
3
+ --
4
+ -- The SDK has always been able to BUILD a custom role (duplicate a system role
5
+ -- in Settings → Permissions, or ask the assistant for one), but the table it
6
+ -- writes to never existed outside one legacy pool: `saas_core.tenant_roles`,
7
+ -- swept into `public` by 0000b and created nowhere else. Everywhere else the
8
+ -- insert threw and the screen swallowed it — a "Criar perfil" button that did
9
+ -- nothing.
10
+ --
11
+ -- Two changes, both required for a custom profile to survive a reload:
12
+ --
13
+ -- 1. public.tenant_roles — the role's IDENTITY (key + name). Its grants live
14
+ -- in tenant_role_overrides, keyed by that same `key`.
15
+ --
16
+ -- 2. tenant_role_overrides.permission_id loses its FK to public.permissions.
17
+ -- That catalog is a legacy of DB-driven RBAC; the feature catalog is now
18
+ -- DECLARED IN CODE by plugins (`declaredFeatures`) and merged at runtime,
19
+ -- so an app can grant `crm.leads.read` on a pool whose permissions table
20
+ -- never heard of plugin-crm. The FK made every such grant fail. The column
21
+ -- stays text in `feature.action` form — the shape agent_guard reads.
22
+ --
23
+ -- Idempotent: safe to re-run, no-ops when already applied.
24
+ -- ============================================================================
25
+
26
+ CREATE TABLE IF NOT EXISTS public.tenant_roles (
27
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
28
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
29
+ -- Stable slug the grants and tenant_members.role point at. Renaming the
30
+ -- profile must never orphan its permissions, so the key is not the name.
31
+ key text NOT NULL,
32
+ name text NOT NULL,
33
+ description text,
34
+ created_at timestamptz NOT NULL DEFAULT now(),
35
+ UNIQUE(tenant_id, key)
36
+ );
37
+
38
+ ALTER TABLE public.tenant_roles ENABLE ROW LEVEL SECURITY;
39
+
40
+ -- Members see their own tenant's roles (the permission screen lists them);
41
+ -- only tenant admins create, rename or delete one.
42
+ DROP POLICY IF EXISTS "tenant_roles_select" ON public.tenant_roles;
43
+ CREATE POLICY "tenant_roles_select" ON public.tenant_roles FOR SELECT
44
+ USING (tenant_id IN (SELECT tenant_id FROM public.tenant_members WHERE user_id = auth.uid()));
45
+
46
+ DROP POLICY IF EXISTS "tenant_roles_manage" ON public.tenant_roles;
47
+ CREATE POLICY "tenant_roles_manage" ON public.tenant_roles FOR ALL
48
+ USING (public.is_tenant_admin(tenant_id));
49
+
50
+ GRANT ALL ON public.tenant_roles TO authenticated, service_role;
51
+
52
+ -- The FK, dropped by lookup rather than by name: pools created before the
53
+ -- rename carry the constraint under whatever name Postgres minted.
54
+ DO $$
55
+ DECLARE
56
+ c record;
57
+ BEGIN
58
+ IF to_regclass('public.tenant_role_overrides') IS NULL THEN
59
+ RETURN;
60
+ END IF;
61
+ FOR c IN
62
+ SELECT con.conname
63
+ FROM pg_constraint con
64
+ JOIN pg_class rel ON rel.oid = con.conrelid
65
+ JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
66
+ JOIN pg_class frel ON frel.oid = con.confrelid
67
+ WHERE nsp.nspname = 'public'
68
+ AND rel.relname = 'tenant_role_overrides'
69
+ AND con.contype = 'f'
70
+ AND frel.relname = 'permissions'
71
+ LOOP
72
+ EXECUTE format('ALTER TABLE public.tenant_role_overrides DROP CONSTRAINT %I', c.conname);
73
+ END LOOP;
74
+ END $$;
package/package.json CHANGED
@@ -3,9 +3,10 @@
3
3
  "fayz": {
4
4
  "status": "beta"
5
5
  },
6
- "version": "0.8.4",
6
+ "version": "0.9.0-next.0",
7
7
  "description": "Fayz SDK database layer — Drizzle schema primitives, spine references, and migration helpers shared across plugins.",
8
8
  "type": "module",
9
+ "sideEffects": false,
9
10
  "main": "./dist/index.cjs",
10
11
  "module": "./dist/index.js",
11
12
  "types": "./dist/index.d.ts",
@@ -37,6 +38,7 @@
37
38
  "database",
38
39
  "schema"
39
40
  ],
41
+ "peerDependencies": {},
40
42
  "scripts": {
41
43
  "build": "tsup && tsc --emitDeclarationOnly --declaration --declarationMap --noEmit false",
42
44
  "dev": "tsup --watch",