Coordinate scoped model reads with bounded streaming state and identity fences
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { api, errorText } from "@/lib/api";
|
||||
import { readDemoBoards } from "@/lib/demo-workspace";
|
||||
import { matchesRef, type Board } from "@/lib/workspace";
|
||||
import { loadCanvasEntry } from "@/lib/canvas-entry";
|
||||
import { createFoundryTransport } from "@/lib/canvas-service/foundry";
|
||||
import type { ProjectEngine } from "@/lib/canvas-runtime/workspace";
|
||||
import { useCanvasRuntimeHost, useCanvasRenderers } from "./canvas-runtime-host";
|
||||
import type { CanvasSnapshot } from "@/lib/canvas-sync";
|
||||
@@ -27,6 +26,7 @@ export default function GraphPage({ workspaceId, boardId }: { workspaceId: strin
|
||||
const [loaded, setLoaded] = useState<Loaded | null>(null);
|
||||
const [error, setError] = useState("");
|
||||
const [retry, setRetry] = useState(0);
|
||||
const navigationGeneration=useRef(0);
|
||||
useEffect(() => {
|
||||
setLoaded(null); setError("");
|
||||
if (demo) {
|
||||
@@ -37,13 +37,14 @@ export default function GraphPage({ workspaceId, boardId }: { workspaceId: strin
|
||||
}
|
||||
let active = true;
|
||||
const controller = new AbortController();
|
||||
loadCanvasEntry({ request: api, workspaceRef: workspaceId, boardRef: boardId, registry: runtimeHost.registry, signal: controller.signal,
|
||||
transport(accountId) { return createFoundryTransport({ accountId, isCurrentIdentity: runtimeHost.bindAccount(accountId) }); },
|
||||
const startingIdentity=runtimeHost.identity();let currentIdentity:(()=>boolean)|undefined;
|
||||
loadCanvasEntry({ request: api, workspaceRef: workspaceId, boardRef: boardId, registry: runtimeHost.registry, signal: controller.signal,navigationGeneration:++navigationGeneration.current,
|
||||
readModel:input=>{const identity=runtimeHost.identity();if(identity.authEpoch!==startingIdentity.authEpoch&&identity.accountId!==input.accountId)throw new Error('identity_changed');currentIdentity=runtimeHost.bindAccount(input.accountId);return runtimeHost.loadModel(input.accountId,input.workspaceId,input.canvasId,{signal:input.signal,navigationGeneration:input.navigationGeneration});},
|
||||
}).then(async result => {
|
||||
if (!active) return;
|
||||
if (!active||currentIdentity&&!currentIdentity()) return;
|
||||
if (result.mode === 'legacy') { setLoaded({ board: result.board, snapshot: result.snapshot, route }); return; }
|
||||
const engine = await runtimeHost.workspace(result.profile.id, result.board.workspace_id).open(result.model.document, result.model.versions);
|
||||
if (active) setLoaded({ board: result.board, engine, route });
|
||||
if (active&&(!currentIdentity||currentIdentity())) setLoaded({ board: result.board, engine, route });
|
||||
})
|
||||
.catch((error) => { if (active) { setError(errorText(error)); if (error.message === "invalid_session") router.replace("/login"); } });
|
||||
return () => { active = false; controller.abort(); };
|
||||
|
||||
Reference in New Issue
Block a user