import { FacadeHandlerError, FacadeRequest, FacadeResponse, FacadeSerialQueue, createRequest, isFacadeRequest } from "./facade-envelope.js"; export const ASSEMBLY_NATIVE_SCHEMA = "freecad-web-assembly/native-type-probe/v1" as const; export const ASSEMBLY_NATIVE_COMMAND = "assembly.nativeTypeProbe" as const; export const ASSEMBLY_NATIVE_FIXTURE = { schema: ASSEMBLY_NATIVE_SCHEMA, module: "Assembly", typeName: "Assembly::AssemblyObject" } as const; export interface AssemblyNativePayload { schema: typeof ASSEMBLY_NATIVE_SCHEMA; module: "Assembly"; typeName: string } export interface AssemblyNativeResult { schema: typeof ASSEMBLY_NATIVE_SCHEMA; module: "Assembly"; typeName: string; initialized: true; source: "freecad-source"; resourcesReleased: true } export interface AssemblyNativeKernel { ccall(name: string, returnType: "number" | "string", argTypes?: string[], args?: unknown[]): number | string } export type AssemblyNativeRequest = FacadeRequest; export type AssemblyNativeResponse = FacadeResponse; export function createAssemblyNativeRequest(id: string, payload: AssemblyNativePayload = ASSEMBLY_NATIVE_FIXTURE): AssemblyNativeRequest { return createRequest(id, ASSEMBLY_NATIVE_COMMAND, payload, "assembly-native"); } export function isAssemblyNativeRequest(value: unknown): value is AssemblyNativeRequest { if (!isFacadeRequest(value)) return false; const request = value as AssemblyNativeRequest; return request.command === ASSEMBLY_NATIVE_COMMAND && request.payload?.schema === ASSEMBLY_NATIVE_SCHEMA && request.payload?.module === "Assembly" && typeof request.payload.typeName === "string" && request.payload.typeName.length > 0; } export async function handleAssemblyNative(payload: AssemblyNativePayload, signal: AbortSignal, source: AssemblyNativeKernel | Promise): Promise { if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled"); if (!isAssemblyNativeRequest(createAssemblyNativeRequest("validation", payload))) throw new FacadeHandlerError("invalid_fixture", "Assembly native type probe payload is invalid"); const kernel = await source; if (signal.aborted) throw new FacadeHandlerError("cancelled", "request was cancelled"); if (Number(kernel.ccall("fc_web_assembly_initialize", "number", ["string"], ["AssemblyApp"])) !== 1) throw new FacadeHandlerError(String(kernel.ccall("fc_web_assembly_error_code", "string") || "native_error"), String(kernel.ccall("fc_web_assembly_error_message", "string") || "Assembly native initialization failed")); if (Number(kernel.ccall("fc_web_assembly_type_probe", "number", ["string"], [payload.typeName])) !== 1) throw new FacadeHandlerError(String(kernel.ccall("fc_web_assembly_error_code", "string") || "type_not_found"), String(kernel.ccall("fc_web_assembly_error_message", "string") || "Assembly type probe failed")); const handle = Number(kernel.ccall("fc_web_assembly_create_handle", "number", ["string"], [payload.typeName])); if (handle <= 0 || Number(kernel.ccall("fc_web_assembly_release_handle", "number", ["number"], [handle])) !== 1 || Number(kernel.ccall("fc_web_assembly_active_handles", "number")) !== 0) throw new FacadeHandlerError("resource_leak", "Assembly native type handle was not released"); return { schema: ASSEMBLY_NATIVE_SCHEMA, module: "Assembly", typeName: String(kernel.ccall("fc_web_assembly_last_type", "string")), initialized: true, source: "freecad-source", resourcesReleased: true }; } export function dispatchAssemblyNative(queue: FacadeSerialQueue, request: AssemblyNativeRequest, source: AssemblyNativeKernel | Promise): Promise { return queue.dispatch(request, (payload, signal) => handleAssemblyNative(payload, signal, source)); }