spine-framework 0.3.86 → 0.3.89

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.
@@ -1,5 +1,5 @@
1
- import { Suspense, lazy } from 'react'
2
- import { Routes, Route } from 'react-router-dom'
1
+ import { Suspense, lazy, useEffect } from 'react'
2
+ import { Routes, Route, Navigate, useNavigate, useLocation } from 'react-router-dom'
3
3
  import { useAuth } from './contexts/AuthContext'
4
4
  import { LoadingSpinner } from './components/ui/LoadingSpinner'
5
5
  import { LoginPage } from './pages/auth/LoginPage'
@@ -53,7 +53,25 @@ function App() {
53
53
  }
54
54
 
55
55
  function AuthenticatedRouter() {
56
+ const { user } = useAuth()
56
57
  const { routableApps: apps, loading } = useAppsRegistry()
58
+ const navigate = useNavigate()
59
+ const location = useLocation()
60
+
61
+ // Where to send an already-authenticated user who lands on /login or /register.
62
+ // System admins go to the framework admin namespace; everyone else goes to the
63
+ // first app they are allowed to access (routableApps is already role-filtered).
64
+ const defaultRedirect = user?.roles?.includes('system_admin')
65
+ ? '/spine-framework/admin'
66
+ : (apps[0]?.route_prefix || '/')
67
+
68
+ // Redirect away from auth pages once apps have loaded.
69
+ // This fires reliably after loading completes, regardless of render timing.
70
+ useEffect(() => {
71
+ if (!loading && ['/login', '/register'].includes(location.pathname)) {
72
+ navigate(defaultRedirect, { replace: true })
73
+ }
74
+ }, [loading, location.pathname, defaultRedirect, navigate])
57
75
 
58
76
  if (loading) {
59
77
  return (
@@ -77,6 +95,9 @@ function AuthenticatedRouter() {
77
95
  return (b.route_prefix?.length || 0) - (a.route_prefix?.length || 0)
78
96
  })
79
97
 
98
+ // Build a valid route path: prefix "/" must become "/*", not "//*"
99
+ const toRoutePath = (prefix: string) => prefix === '/' ? '/*' : `${prefix}/*`
100
+
80
101
  return (
81
102
  <Suspense fallback={<div className="min-h-screen flex items-center justify-center"><LoadingSpinner /></div>}>
82
103
  <Routes>
@@ -85,8 +106,8 @@ function AuthenticatedRouter() {
85
106
  <Route path="/spine-framework/api" element={<APIPage />} />
86
107
  <Route path="/spine-framework/cli" element={<CLIPage />} />
87
108
 
88
- {/* Auth routes for already-authenticated users (LoginPage handles redirect) */}
89
- <Route path="/login" element={<LoginPage />} />
109
+ {/* Auth routes: redirect handled by useEffect above, but keep as fallback */}
110
+ <Route path="/login" element={<Navigate to={defaultRedirect} replace />} />
90
111
  <Route path="/register" element={<RegisterPage />} />
91
112
 
92
113
  {/* Dynamic app routes — no framework opinions about / or /dashboard */}
@@ -97,7 +118,7 @@ function AuthenticatedRouter() {
97
118
  return (
98
119
  <Route
99
120
  key={app.slug}
100
- path={`${prefix}/*`}
121
+ path={toRoutePath(prefix)}
101
122
  element={
102
123
  <AppWrapper app={app}>
103
124
  <CustomAppLoader slug={app.slug} />
@@ -111,7 +132,7 @@ function AuthenticatedRouter() {
111
132
  return (
112
133
  <Route
113
134
  key={app.slug}
114
- path={`${prefix}/*`}
135
+ path={toRoutePath(prefix)}
115
136
  element={
116
137
  <AppWrapper app={app}>
117
138
  <GenericAppShell app={app} />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework",
3
- "version": "0.3.86",
3
+ "version": "0.3.89",
4
4
  "description": "Multi-tenant, modular application platform for modern SaaS systems",
5
5
  "type": "module",
6
6
  "bin": {
@@ -84,9 +84,6 @@
84
84
  "docs": "typedoc --entryPoints .framework/functions/_shared/index.ts --out docs/generated"
85
85
  },
86
86
  "dependencies": {
87
- "tsx": "^4.21.0",
88
- "ws": "^8.18.0",
89
- "pg": "^8.13.0",
90
87
  "@base-ui/react": "^1.4.1",
91
88
  "@fontsource-variable/inter": "^5.2.8",
92
89
  "@heroicons/react": "^2.2.0",
@@ -138,6 +135,7 @@
138
135
  "marked": "^17.0.3",
139
136
  "mermaid": "^11.12.3",
140
137
  "next-themes": "^0.4.6",
138
+ "pg": "^8.13.0",
141
139
  "radix-ui": "^1.4.3",
142
140
  "react": "^18.3.1",
143
141
  "react-day-picker": "^10.0.0",
@@ -155,11 +153,14 @@
155
153
  "remark-gfm": "^4.0.1",
156
154
  "shadcn": "^4.7.0",
157
155
  "sonner": "^2.0.7",
156
+ "spine-framework-cortex": "^0.2.12",
158
157
  "tailwind-merge": "^3.5.0",
159
158
  "tailwindcss-animate": "^1.0.7",
160
159
  "tiptap-markdown": "^0.9.0",
160
+ "tsx": "^4.21.0",
161
161
  "tw-animate-css": "^1.4.0",
162
- "vaul": "^1.1.2"
162
+ "vaul": "^1.1.2",
163
+ "ws": "^8.18.0"
163
164
  },
164
165
  "devDependencies": {
165
166
  "@netlify/functions": "^2.8.2",
package/spine.config.json CHANGED
@@ -6,14 +6,19 @@
6
6
  "allow_url_override": true,
7
7
  "apps": {
8
8
  "portal": {
9
- "roles": ["member"],
9
+ "roles": [
10
+ "member"
11
+ ],
10
12
  "default_role": "member",
11
13
  "path": "/portal",
12
14
  "enabled": true,
13
15
  "account_strategy": "new"
14
16
  },
15
17
  "cortex": {
16
- "roles": ["support", "support_admin"],
18
+ "roles": [
19
+ "support",
20
+ "support_admin"
21
+ ],
17
22
  "default_role": "support",
18
23
  "path": "/cortex",
19
24
  "enabled": true,