spine-framework 0.3.93 → 0.3.94

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.
@@ -84,11 +84,15 @@ export function AppsRegistryProvider({ children }: AppsRegistryProviderProps) {
84
84
  const [loading, setLoading] = useState(true)
85
85
  const [error, setError] = useState<string | null>(null)
86
86
  const abortRef = useRef<AbortController | null>(null)
87
+ // Track which user the current `apps` + `loading` state belongs to.
88
+ // When user changes, we know to treat state as stale until the new fetch lands.
89
+ const loadedForUserRef = useRef<string | null>(null)
87
90
 
88
91
  const fetchApps = useCallback(async (signal?: AbortSignal) => {
89
92
  if (!user) {
90
93
  setApps([])
91
94
  setLoading(false)
95
+ loadedForUserRef.current = null
92
96
  return
93
97
  }
94
98
 
@@ -108,6 +112,7 @@ export function AppsRegistryProvider({ children }: AppsRegistryProviderProps) {
108
112
  // Backend already filters by role — no client-side role check needed
109
113
  const allApps: AppRecord[] = data.data || data || []
110
114
  setApps(allApps)
115
+ loadedForUserRef.current = user.id
111
116
  } catch (err) {
112
117
  if (err instanceof DOMException && err.name === 'AbortError') return
113
118
  setError(err instanceof Error ? err.message : 'Failed to load apps')
@@ -131,6 +136,10 @@ export function AppsRegistryProvider({ children }: AppsRegistryProviderProps) {
131
136
  return () => controller.abort()
132
137
  }, [user?.id, user?.account_id, rolesKey, fetchApps])
133
138
 
139
+ // Derive effective loading: if user changed but we haven't fetched for them
140
+ // yet (effect hasn't fired), treat as loading to prevent 404 flash.
141
+ const effectiveLoading = loading || (!!user && loadedForUserRef.current !== user.id)
142
+
134
143
  const routableApps = apps.filter(
135
144
  app => app.route_prefix != null && app.renderer !== 'none'
136
145
  )
@@ -143,7 +152,7 @@ export function AppsRegistryProvider({ children }: AppsRegistryProviderProps) {
143
152
  }, [fetchApps])
144
153
 
145
154
  return (
146
- <AppsRegistryContext.Provider value={{ apps, routableApps, loading, error, refetch }}>
155
+ <AppsRegistryContext.Provider value={{ apps, routableApps, loading: effectiveLoading, error, refetch }}>
147
156
  {children}
148
157
  </AppsRegistryContext.Provider>
149
158
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework",
3
- "version": "0.3.93",
3
+ "version": "0.3.94",
4
4
  "description": "Multi-tenant, modular application platform for modern SaaS systems",
5
5
  "type": "module",
6
6
  "bin": {