import { FacadeHandlerError, FacadeRequest, FacadeResponse, FacadeSerialQueue, createRequest, isFacadeRequest } from "./facade-envelope.js"; export const IMPORT_PYTHON_FAMILY_SCHEMA = "freecad-web-import/python-family-batch/v1" as const; export const IMPORT_PYTHON_FAMILY_COMMAND = "import.pythonFamilyBatch" as const; export interface ImportPythonFamilyRecord { apiId: string; name: string; family: string; sourcePath?: string; disposition?: "exposed" | "restricted" | "nonportable" | "planned" | "not_implemented"; } export type ImportPythonFamilyTier = "tier-1-readonly" | "tier-2-pure" | "tier-3-stateful" | "object-contract"; export interface ImportPythonFamilyPayload { schema: typeof IMPORT_PYTHON_FAMILY_SCHEMA; module: "Import"; tier: ImportPythonFamilyTier; records: ImportPythonFamilyRecord[]; } export interface ImportPythonFamilyNativeRecord extends ImportPythonFamilyRecord { status: "exposed" | "restricted" | "nonportable" | "not_implemented"; code: string; message: string; native: true; sourceEntry?: string; sourceRevision?: string; } export interface ImportPythonFamilyResult { schema: typeof IMPORT_PYTHON_FAMILY_SCHEMA; module: "Import"; tier: ImportPythonFamilyTier; source: "freecad-source"; records: ImportPythonFamilyNativeRecord[]; count: number; resourcesReleased: true; } export type ImportPythonFamilyRequest = FacadeRequest; export type ImportPythonFamilyResponse = FacadeResponse; export function createImportPythonFamilyRequest(requestId: string, records: ImportPythonFamilyRecord[], tier: ImportPythonFamilyTier = "tier-1-readonly"): ImportPythonFamilyRequest { return createRequest(requestId, IMPORT_PYTHON_FAMILY_COMMAND, { schema: IMPORT_PYTHON_FAMILY_SCHEMA, module: "Import", tier, records }, "import-python-family"); } export function isImportPythonFamilyRequest(value: unknown): value is ImportPythonFamilyRequest { if (!isFacadeRequest(value)) return false; const request = value as ImportPythonFamilyRequest; const payload = request.payload; return request.command === IMPORT_PYTHON_FAMILY_COMMAND && payload?.schema === IMPORT_PYTHON_FAMILY_SCHEMA && payload?.module === "Import" && (payload?.tier === "tier-1-readonly" || payload?.tier === "tier-2-pure" || payload?.tier === "tier-3-stateful" || payload?.tier === "object-contract") && Array.isArray(payload.records) && payload.records.length > 0 && payload.records.every((record) => record && typeof record.apiId === "string" && typeof record.name === "string" && typeof record.family === "string"); } type ImportKernel = { ccall(name: string, returnType: "number" | "string", argTypes?: string[], args?: unknown[]): number | string }; function dispatchJson(kernel: ImportKernel, payload: ImportPythonFamilyPayload): ImportPythonFamilyResult { const raw = String(kernel.ccall("fc_web_dispatch_json", "string", ["string"], [JSON.stringify({ cmd: IMPORT_PYTHON_FAMILY_COMMAND, args: { tier: payload.tier, records: payload.records } })])); let reply: unknown; try { reply = JSON.parse(raw); } catch { throw new FacadeHandlerError("native_protocol_error", "Import native dispatcher returned invalid JSON"); } if (!reply || typeof reply !== "object") throw new FacadeHandlerError("native_protocol_error", "Import native dispatcher returned a non-object result"); const result = reply as Record; if (result.ok !== true) throw new FacadeHandlerError(String(result.code || "native_error"), String(result.error || "Import Python family dispatch failed")); if (result.schema !== IMPORT_PYTHON_FAMILY_SCHEMA || result.module !== "Import" || result.tier !== payload.tier || result.source !== "freecad-source") throw new FacadeHandlerError("native_protocol_error", "Import native dispatcher returned an invalid batch schema"); if (!Array.isArray(result.records) || result.records.length !== payload.records.length || result.count !== payload.records.length || result.resourcesReleased !== true) throw new FacadeHandlerError("native_protocol_error", "Import native dispatcher returned an incomplete record set"); if (result.records.some((record) => !record || typeof record !== "object" || !["exposed", "restricted", "nonportable", "not_implemented"].includes(String((record as Record).status)) || (record as Record).native !== true)) throw new FacadeHandlerError("native_protocol_error", "Import native dispatcher returned an invalid record status"); return result as unknown as ImportPythonFamilyResult; } export async function handleImportPythonFamily(payload: ImportPythonFamilyPayload, signal: AbortSignal, source: ImportKernel | Promise): Promise { if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled"); if (!isImportPythonFamilyRequest(createImportPythonFamilyRequest("validation", payload.records))) throw new FacadeHandlerError("invalid_fixture", "Import Python family payload is invalid"); const kernel = await source; if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled"); return dispatchJson(kernel, payload); } export function dispatchImportPythonFamily(queue: FacadeSerialQueue, request: ImportPythonFamilyRequest, source: ImportKernel | Promise): Promise { return queue.dispatch(request, (payload, signal) => handleImportPythonFamily(payload, signal, source)); }