|
1 | | -import { type ServerLifecycleWelcomePayload } from "@t3tools/contracts"; |
| 1 | +import { type EnvironmentId, type ServerLifecycleWelcomePayload } from "@t3tools/contracts"; |
2 | 2 | import { scopedProjectKey, scopeProjectRef } from "@t3tools/client-runtime"; |
3 | 3 | import { |
4 | 4 | Outlet, |
@@ -44,15 +44,18 @@ import { useStore } from "../store"; |
44 | 44 | import { useUiStateStore } from "../uiStateStore"; |
45 | 45 | import { syncBrowserChromeTheme } from "../hooks/useTheme"; |
46 | 46 | import { |
| 47 | + disconnectPrimaryEnvironment, |
47 | 48 | ensureEnvironmentConnectionBootstrapped, |
48 | 49 | getPrimaryEnvironmentConnection, |
49 | 50 | startEnvironmentConnectionService, |
50 | 51 | } from "../environments/runtime"; |
51 | 52 | import { configureClientTracing } from "../observability/clientTracing"; |
52 | 53 | import { |
53 | 54 | ensurePrimaryEnvironmentReady, |
| 55 | + readPrimaryEnvironmentDescriptor, |
54 | 56 | resolveInitialServerAuthGateState, |
55 | 57 | updatePrimaryEnvironmentDescriptor, |
| 58 | + usePrimaryEnvironmentId, |
56 | 59 | } from "../environments/primary"; |
57 | 60 |
|
58 | 61 | export const Route = createRootRouteWithContext<{ |
@@ -187,7 +190,12 @@ function errorDetails(error: unknown): string { |
187 | 190 | } |
188 | 191 |
|
189 | 192 | function ServerStateBootstrap() { |
190 | | - useEffect(() => startServerStateSync(getPrimaryEnvironmentConnection().client.server), []); |
| 193 | + const primaryEnvironmentId = usePrimaryEnvironmentId(); |
| 194 | + |
| 195 | + useEffect( |
| 196 | + () => startServerStateSync(getPrimaryEnvironmentConnection().client.server), |
| 197 | + [primaryEnvironmentId], |
| 198 | + ); |
191 | 199 |
|
192 | 200 | return null; |
193 | 201 | } |
@@ -222,11 +230,31 @@ function EventRouter() { |
222 | 230 | const handledBootstrapThreadIdRef = useRef<string | null>(null); |
223 | 231 | const seenServerConfigUpdateIdRef = useRef(getServerConfigUpdatedNotification()?.id ?? 0); |
224 | 232 | const disposedRef = useRef(false); |
| 233 | + const primaryEnvironmentIdRef = useRef<EnvironmentId | null>( |
| 234 | + readPrimaryEnvironmentDescriptor()?.environmentId ?? null, |
| 235 | + ); |
225 | 236 | const serverConfig = useServerConfig(); |
226 | 237 |
|
| 238 | + const reconcilePrimaryEnvironment = useEffectEvent((nextEnvironmentId: EnvironmentId) => { |
| 239 | + const previousEnvironmentId = primaryEnvironmentIdRef.current; |
| 240 | + primaryEnvironmentIdRef.current = nextEnvironmentId; |
| 241 | + if (!previousEnvironmentId || previousEnvironmentId === nextEnvironmentId) { |
| 242 | + return; |
| 243 | + } |
| 244 | + |
| 245 | + void disconnectPrimaryEnvironment(previousEnvironmentId); |
| 246 | + useStore.getState().clearPrimaryEnvironmentState(previousEnvironmentId); |
| 247 | + |
| 248 | + const routeEnvironmentId = readPathname().split("/").filter(Boolean)[0] ?? null; |
| 249 | + if (routeEnvironmentId === previousEnvironmentId) { |
| 250 | + void navigate({ to: "/", replace: true }); |
| 251 | + } |
| 252 | + }); |
| 253 | + |
227 | 254 | const handleWelcome = useEffectEvent((payload: ServerLifecycleWelcomePayload | null) => { |
228 | 255 | if (!payload) return; |
229 | 256 |
|
| 257 | + reconcilePrimaryEnvironment(payload.environment.environmentId); |
230 | 258 | updatePrimaryEnvironmentDescriptor(payload.environment); |
231 | 259 | setActiveEnvironmentId(payload.environment.environmentId); |
232 | 260 | void (async () => { |
@@ -339,9 +367,10 @@ function EventRouter() { |
339 | 367 | return; |
340 | 368 | } |
341 | 369 |
|
| 370 | + reconcilePrimaryEnvironment(serverConfig.environment.environmentId); |
342 | 371 | updatePrimaryEnvironmentDescriptor(serverConfig.environment); |
343 | 372 | setActiveEnvironmentId(serverConfig.environment.environmentId); |
344 | | - }, [serverConfig, setActiveEnvironmentId]); |
| 373 | + }, [reconcilePrimaryEnvironment, serverConfig, setActiveEnvironmentId]); |
345 | 374 |
|
346 | 375 | useEffect(() => { |
347 | 376 | disposedRef.current = false; |
|
0 commit comments