spine-framework 0.3.68 → 0.3.70

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,6 +248,10 @@ 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
+ // 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
254
+ min_role: manifest.required_roles?.[0] ?? manifest.min_role ?? null,
251
255
  },
252
256
  { onConflict: 'slug' }
253
257
  )
@@ -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
- if (app.min_role) {
28
- const hasRole = user.roles?.includes('system_admin') || user.roles?.includes(app.min_role)
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> {app.min_role}</p>
47
+ <p className="text-sm text-slate-600"><strong>Required (any):</strong> {requiredRoles.join(', ')}</p>
43
48
  </div>
44
49
  </div>
45
50
  </div>
@@ -300,10 +300,12 @@ export function RegisterPage() {
300
300
  }
301
301
 
302
302
  // Handle account creation vs existing account assignment
303
+ // IMPORTANT: use effectiveAccountStrategy (local var), NOT accountStrategy (React state)
304
+ // React state updates are async — accountStrategy may still hold the previous value here
303
305
  let registrationResult
304
- console.log('Registration decision:', { accountStrategy, targetAccount, effectiveRole })
306
+ console.log('Registration decision:', { effectiveAccountStrategy, targetAccount, effectiveRole })
305
307
 
306
- if (accountStrategy === 'existing' && targetAccount) {
308
+ if (effectiveAccountStrategy === 'existing' && targetAccount) {
307
309
  // Assign to existing account
308
310
  console.log('Using existing_account path')
309
311
  registrationResult = await callInvitesApi('complete-registration', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework",
3
- "version": "0.3.68",
3
+ "version": "0.3.70",
4
4
  "description": "Multi-tenant, modular application platform for modern SaaS systems",
5
5
  "type": "module",
6
6
  "bin": {