import { encodeToolcraftModelDocument } from "../canonical/model-document-codec"; import { digestToolcraftModelDocument } from "../canonical/model-document-digest"; import { createValidModelDocument } from "../canonical/model-document-test-support"; import { TOOLCRAFT_DEFAULT_MODEL_IMPORT_LIMITS } from "../model-import-limits"; import { digestModelSourceBytes } from "../model-source-digest"; import { encodeToolcraftModelRepairPlanEnvelope } from "../topology/model-repair-plan-codec"; import type { ToolcraftModelRepairPlan } from "../topology/model-repair-plan"; import { digestToolcraftRepairPlanPayload, digestToolcraftTopologyDocument, } from "../topology/model-topology-digest"; import { digestToolcraftModelWorkerBytes } from "./model-import-worker-receipt"; import type { ToolcraftModelWorkerRequest } from "./model-import-worker-protocol"; export const limits = TOOLCRAFT_DEFAULT_MODEL_IMPORT_LIMITS; export function sourceBuffer(value = 1): ArrayBuffer { return new Uint8Array([value, value + 1, value + 2]).buffer; } export function encodedDocumentBuffer(): ArrayBuffer { return copyArrayBuffer(encodeToolcraftModelDocument(createValidModelDocument())); } export function copyArrayBuffer(bytes: Uint8Array): ArrayBuffer { const copy = new Uint8Array(bytes.byteLength); copy.set(bytes); return copy.buffer; } export function decodeRequest( generation: number, profile: "realtime-mesh" | "solid-mesh" = "realtime-mesh", sourceValue = 1, ): ToolcraftModelWorkerRequest { const bytes = sourceBuffer(sourceValue); return { generation, jobId: `decode-${generation}`, kind: "decode-and-analyze", payload: { adapterVersion: "test-adapter@1", bundle: { aggregateDigest: "sha256:source", rootPath: "model.glb", sourceFiles: [{ bytes, contentDigest: digestModelSourceBytes(new Uint8Array(bytes)), mimeType: "model/gltf-binary", path: "model.glb", }], }, format: "glb", geometryDecoderVersion: "test-decoder@1", limits, topologyProfile: profile, }, }; } export function withClaimedAggregateDigest( request: ToolcraftModelWorkerRequest, aggregateDigest: string, ): ToolcraftModelWorkerRequest { if (request.kind !== "decode-and-analyze") { throw new Error("Expected decode request."); } return { ...request, payload: { ...request.payload, bundle: { ...request.payload.bundle, aggregateDigest }, }, }; } export function repairRequest( generation: number, plan: ToolcraftModelRepairPlan, ): ToolcraftModelWorkerRequest { const document = createValidModelDocument(); const envelopeBytes = encodeToolcraftModelRepairPlanEnvelope(plan); return { generation, jobId: `repair-${generation}`, kind: "repair", payload: { canonicalDocument: encodedDocumentBuffer(), canonicalDocumentDigest: digestToolcraftModelDocument(document), limits, repairPlanEnvelope: { bytes: envelopeBytes.buffer, envelopeDigest: digestToolcraftModelWorkerBytes(envelopeBytes), planDigest: plan.planDigest, version: 1, }, }, }; } export function fakeRepairPlan( salt = "one", ): ToolcraftModelRepairPlan { const operations = Object.freeze([Object.freeze({ expectedCountDelta: Object.freeze({ triangles: 0, vertices: 0 }), primitiveId: "primitive-1", primitiveIndex: 0, safetyPreconditions: Object.freeze([`positions are finite XYZ triples:${salt}`]), type: "recalculate-bounds" as const, })]); const payload = { algorithmVersion: "toolcraft-safe-repair@1", analyzerVersion: "toolcraft-topology@1", operations, profile: "realtime-mesh" as const, sourceDocumentDigest: digestToolcraftTopologyDocument( createValidModelDocument(), ), }; const planDigest = digestToolcraftRepairPlanPayload(payload); return Object.freeze({ ...payload, planDigest, recipeId: `toolcraft-safe-repair@1:${planDigest}`, }); }