import { FacadeHandlerError, FacadeRequest, FacadeResponse, FacadeSerialQueue, createRequest, isFacadeRequest, } from "./facade-envelope.js"; export const TECHDRAW_SCHEMA = "freecad-web-techdraw/frontend-drawing/v1" as const; export const TECHDRAW_COMMAND = "techdraw.createRecompute" as const; export interface TechDrawBox { length: number; width: number; height: number } export interface TechDrawPayload { schema: typeof TECHDRAW_SCHEMA; module: "TechDraw"; action: "create/recompute"; documentId?: string; box?: TechDrawBox; } export const TECHDRAW_FIXTURE: TechDrawPayload = { schema: TECHDRAW_SCHEMA, module: "TechDraw", action: "create/recompute", box: { length: 40, width: 24, height: 18 }, }; export interface TechDrawResult { schema: typeof TECHDRAW_SCHEMA; module: "TechDraw"; action: "create/recompute"; source: "freecad-source"; box: TechDrawBox; volume: number; renderer: "TechDraw.viewPartAsSvg"; nativeSource: "TechDraw::DrawViewPart"; svg: string; bounds: [number, number, number, number]; edgeCount: number; document: { name: string; objectCount: number; keptOpen: true }; page: string; pageSize: [number, number]; view: string; } export interface TechDrawKernel { ccall(name: string, type: "number" | "string", argTypes?: string[], args?: unknown[]): number | string; } export type TechDrawRequest = FacadeRequest; export type TechDrawResponse = FacadeResponse; export function createTechDrawRequest(id: string, payload: TechDrawPayload = TECHDRAW_FIXTURE): TechDrawRequest { return createRequest(id, TECHDRAW_COMMAND, payload, payload.documentId ?? "TechDrawDrawing"); } export function isTechDrawRequest(value: unknown): value is TechDrawRequest { if (!isFacadeRequest(value)) return false; const request = value as TechDrawRequest; const p = request.payload; return request.command === TECHDRAW_COMMAND && p?.schema === TECHDRAW_SCHEMA && p.module === "TechDraw" && p.action === "create/recompute" && (p.documentId === undefined || typeof p.documentId === "string") && (p.box === undefined || (typeof p.box?.length === "number" && typeof p.box?.width === "number" && typeof p.box?.height === "number")); } export async function handleTechDraw(p: TechDrawPayload, signal: AbortSignal, source: TechDrawKernel | Promise): Promise { if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled"); if (!isTechDrawRequest(createTechDrawRequest("validation", p)) || (p.box && ![p.box.length, p.box.width, p.box.height].every(value => Number.isFinite(value) && value > 0))) throw new FacadeHandlerError("invalid_request", "Box dimensions must be positive finite numbers"); const kernel = await source; if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled"); let value: TechDrawResult & { ok?: boolean; error?: string; code?: string }; try { value = JSON.parse(String(kernel.ccall("fc_web_dispatch_json", "string", ["string"], [JSON.stringify({ cmd: TECHDRAW_COMMAND, args: p })]))); } catch { throw new FacadeHandlerError("native_protocol_error", "TechDraw native dispatcher returned invalid JSON"); } if (!value || typeof value !== "object") throw new FacadeHandlerError("native_protocol_error", "TechDraw native response must be an object"); if (value.ok !== true) throw new FacadeHandlerError(value.code ?? "native_error", value.error ?? "TechDraw drawing failed"); if (value.schema !== TECHDRAW_SCHEMA || value.module !== "TechDraw" || value.source !== "freecad-source" || value.renderer !== "TechDraw.viewPartAsSvg" || value.nativeSource !== "TechDraw::DrawViewPart" || value.action !== "create/recompute" || !Number.isFinite(value.volume) || value.volume <= 0 || !value.box || ![value.box.length, value.box.width, value.box.height].every(n => Number.isFinite(n) && n > 0) || (p.box && (value.box.length !== p.box.length || value.box.width !== p.box.width || value.box.height !== p.box.height)) || value.document?.name !== (p.documentId ?? "TechDrawDrawing") || value.document.keptOpen !== true || !Number.isInteger(value.document.objectCount) || value.document.objectCount < 4 || value.page !== "Page" || value.view !== "View" || !Array.isArray(value.pageSize) || value.pageSize.length !== 2 || !value.pageSize.every(n => Number.isFinite(n) && n > 0) || typeof value.svg !== "string" || !value.svg.includes("): Promise { return queue.dispatch(request, (payload, signal) => handleTechDraw(payload, signal, source)); }