Files
Endoleap/src/lib/canvas-entry.ts
T

29 lines
2.6 KiB
TypeScript

import type {LiveModelPreview} from './canvas-runtime/model-preview.ts';
import type { Profile } from './api.ts';
import type { CanvasRequest } from './canvas-sync.ts';
import { decodeSnapshot } from './canvas-sync.ts';
import { CANVAS_ACCEPT } from './canvas-v2.ts';
import { matchesRef, type Board } from './workspace.ts';
import type { Registry } from './canvas-core/types.ts';
import { loadFoundryModel, type ModelLoad, type ServiceTransport } from './canvas-service/foundry.ts';
/** Read canonical first: a migrated project must never be opened through snapshot writers. */
export async function loadCanvasEntry(options: { request: CanvasRequest; workspaceRef: string; boardRef: string; registry: Registry; transport?(accountId: string): ServiceTransport; readModel?(input:{accountId:string;workspaceId:string;canvasId:string;signal?:AbortSignal;navigationGeneration:number;onPreview?:(preview:LiveModelPreview)=>void}):Promise<ModelLoad>;onPreview?:(preview:LiveModelPreview,board:Board,profile:Profile)=>void;signal?: AbortSignal;navigationGeneration?:number }) {
const path = `workspaces/${encodeURIComponent(options.workspaceRef)}/materials/${encodeURIComponent(options.boardRef)}`;
const [board, profile] = await Promise.all([options.request<Board>(path, { signal: options.signal }), options.request<Profile>('profile', { signal: options.signal })]);
options.signal?.throwIfAborted();
if (board.kind !== 'board' || !matchesRef(board, options.boardRef) || !board.workspace_id || !profile.id) throw new Error('invalid_reference');
if(!options.readModel&&!options.transport)throw new Error('model_loader_unavailable');
try {
const model = options.readModel?await options.readModel({accountId:profile.id,workspaceId:board.workspace_id,canvasId:board.id,signal:options.signal,navigationGeneration:options.navigationGeneration??0,...(options.onPreview?{onPreview:(preview:LiveModelPreview)=>options.onPreview!(preview,board,profile)}:{})}):await loadFoundryModel(options.transport!(profile.id), board.workspace_id, board.id, options.registry, options.signal);
options.signal?.throwIfAborted();
if (model.status === 'ready') return { mode: 'headless' as const, board, profile, model };
// Existing projects keep their current editor until the user explicitly migrates them.
} catch (error) {
options.signal?.throwIfAborted();
if ((error as { code?: string }).code !== 'not_found') throw error;
}
const snapshot = decodeSnapshot(await options.request(path + '/canvas', { signal: options.signal, headers: { Accept: CANVAS_ACCEPT } }));
return { mode: 'legacy' as const, board, profile, snapshot };
}