spine-framework 0.3.69 → 0.3.71
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.
|
@@ -248,7 +248,9 @@ async function seedApp(appDir: string, appSlug: string) {
|
|
|
248
248
|
is_active: true,
|
|
249
249
|
route_prefix: manifest.route_prefix ?? ('/' + appSlug),
|
|
250
250
|
renderer: manifest.renderer ?? 'custom',
|
|
251
|
-
//
|
|
251
|
+
// required_roles: full array from manifest (e.g. ["support", "support_admin"])
|
|
252
|
+
required_roles: manifest.required_roles ?? (manifest.min_role ? [manifest.min_role] : []),
|
|
253
|
+
// min_role: kept as legacy fallback — first entry of required_roles
|
|
252
254
|
min_role: manifest.required_roles?.[0] ?? manifest.min_role ?? null,
|
|
253
255
|
},
|
|
254
256
|
{ onConflict: 'slug' }
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
-- Migration 017: Fix get_account_apps() to include globally-available apps
|
|
2
|
+
--
|
|
3
|
+
-- Problem: The RPC function excluded apps where owner_account_id IS NULL,
|
|
4
|
+
-- meaning installed apps (source='npm', owner_account_id=NULL) were invisible
|
|
5
|
+
-- to all users in the apps list.
|
|
6
|
+
--
|
|
7
|
+
-- Fix: Include apps where owner_account_id IS NULL (globally available apps).
|
|
8
|
+
|
|
9
|
+
CREATE OR REPLACE FUNCTION public.get_account_apps(
|
|
10
|
+
account_id uuid,
|
|
11
|
+
include_system boolean DEFAULT true,
|
|
12
|
+
include_inactive boolean DEFAULT false
|
|
13
|
+
)
|
|
14
|
+
RETURNS TABLE(
|
|
15
|
+
id uuid,
|
|
16
|
+
slug text,
|
|
17
|
+
name text,
|
|
18
|
+
description text,
|
|
19
|
+
icon text,
|
|
20
|
+
color text,
|
|
21
|
+
version text,
|
|
22
|
+
app_type text,
|
|
23
|
+
source text,
|
|
24
|
+
owner_account_id uuid,
|
|
25
|
+
is_active boolean,
|
|
26
|
+
is_system boolean,
|
|
27
|
+
min_role text,
|
|
28
|
+
config jsonb,
|
|
29
|
+
nav_items jsonb,
|
|
30
|
+
route_prefix text,
|
|
31
|
+
renderer text,
|
|
32
|
+
metadata jsonb,
|
|
33
|
+
integration_deps jsonb,
|
|
34
|
+
created_at timestamptz
|
|
35
|
+
)
|
|
36
|
+
LANGUAGE plpgsql
|
|
37
|
+
SECURITY DEFINER
|
|
38
|
+
AS $$
|
|
39
|
+
BEGIN
|
|
40
|
+
RETURN QUERY
|
|
41
|
+
SELECT
|
|
42
|
+
a.id,
|
|
43
|
+
a.slug,
|
|
44
|
+
a.name,
|
|
45
|
+
a.description,
|
|
46
|
+
a.icon,
|
|
47
|
+
a.color,
|
|
48
|
+
a.version,
|
|
49
|
+
a.app_type,
|
|
50
|
+
a.source,
|
|
51
|
+
a.owner_account_id,
|
|
52
|
+
a.is_active,
|
|
53
|
+
a.is_system,
|
|
54
|
+
a.min_role,
|
|
55
|
+
a.config,
|
|
56
|
+
a.nav_items,
|
|
57
|
+
a.route_prefix,
|
|
58
|
+
a.renderer,
|
|
59
|
+
a.metadata,
|
|
60
|
+
a.integration_deps,
|
|
61
|
+
a.created_at
|
|
62
|
+
FROM public.apps a
|
|
63
|
+
WHERE
|
|
64
|
+
(include_inactive OR a.is_active = true)
|
|
65
|
+
AND (
|
|
66
|
+
a.is_system = true -- always include system apps
|
|
67
|
+
OR a.owner_account_id = get_account_apps.account_id -- owned by this account
|
|
68
|
+
OR a.owner_account_id IS NULL -- globally available (npm-installed apps)
|
|
69
|
+
)
|
|
70
|
+
ORDER BY
|
|
71
|
+
a.is_system DESC,
|
|
72
|
+
a.app_type,
|
|
73
|
+
a.name;
|
|
74
|
+
END;
|
|
75
|
+
$$;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- Migration 018: Add required_roles array to apps table
|
|
2
|
+
--
|
|
3
|
+
-- min_role (single string) only supports one role gate.
|
|
4
|
+
-- required_roles (jsonb array) supports gating by any of several roles.
|
|
5
|
+
-- e.g. ["support", "support_admin"] — user needs either role to access the app.
|
|
6
|
+
--
|
|
7
|
+
-- Both columns coexist. required_roles takes precedence at runtime;
|
|
8
|
+
-- min_role is kept as a legacy fallback and for display purposes.
|
|
9
|
+
|
|
10
|
+
ALTER TABLE public.apps
|
|
11
|
+
ADD COLUMN IF NOT EXISTS required_roles jsonb DEFAULT '[]'::jsonb;
|
|
12
|
+
|
|
13
|
+
-- Backfill: migrate existing min_role values into the array
|
|
14
|
+
UPDATE public.apps
|
|
15
|
+
SET required_roles = jsonb_build_array(min_role)
|
|
16
|
+
WHERE min_role IS NOT NULL
|
|
17
|
+
AND (required_roles = '[]'::jsonb OR required_roles IS NULL);
|
|
@@ -23,9 +23,14 @@ export function AppWrapper({ app, children }: AppWrapperProps) {
|
|
|
23
23
|
return <Navigate to="/login" replace />
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
// Role gate
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
// Role gate — check required_roles array (preferred) or min_role (fallback)
|
|
27
|
+
const requiredRoles: string[] = app.required_roles?.length
|
|
28
|
+
? app.required_roles
|
|
29
|
+
: app.min_role ? [app.min_role] : []
|
|
30
|
+
|
|
31
|
+
if (requiredRoles.length > 0) {
|
|
32
|
+
const hasRole = user.roles?.includes('system_admin') ||
|
|
33
|
+
requiredRoles.some(r => user.roles?.includes(r))
|
|
29
34
|
if (!hasRole) {
|
|
30
35
|
return (
|
|
31
36
|
<div className="min-h-screen flex items-center justify-center bg-slate-50">
|
|
@@ -39,7 +44,7 @@ export function AppWrapper({ app, children }: AppWrapperProps) {
|
|
|
39
44
|
<p className="text-slate-600 mb-6">You don't have permission to access {app.name}.</p>
|
|
40
45
|
<div className="bg-slate-100 rounded-lg p-4 text-left">
|
|
41
46
|
<p className="text-sm text-slate-600 mb-2"><strong>Your roles:</strong> {user.roles?.join(', ') || 'None'}</p>
|
|
42
|
-
<p className="text-sm text-slate-600"><strong>Required:</strong> {
|
|
47
|
+
<p className="text-sm text-slate-600"><strong>Required (any):</strong> {requiredRoles.join(', ')}</p>
|
|
43
48
|
</div>
|
|
44
49
|
</div>
|
|
45
50
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spine-framework",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.71",
|
|
4
4
|
"description": "Multi-tenant, modular application platform for modern SaaS systems",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
".framework/migrations/005_auth_user_trigger.sql",
|
|
24
24
|
".framework/migrations/006_fix_current_actor_id.sql",
|
|
25
25
|
".framework/migrations/016_invites.sql",
|
|
26
|
+
".framework/migrations/017_fix_get_account_apps.sql",
|
|
27
|
+
".framework/migrations/018_apps_required_roles.sql",
|
|
26
28
|
".framework/public/",
|
|
27
29
|
".framework/scripts/",
|
|
28
30
|
".framework/seeds/",
|