{"version":3,"file":"index.cjs","sources":["../src/presets.ts","../src/index.ts"],"sourcesContent":["/**\n * MeshRepair - WebAssembly STL Mesh Repair Library\n *\n * Preset configurations for common repair operations\n *\n * SPDX-License-Identifier: GPL-3.0\n */\n\nimport type { RepairOptions, PresetName } from './types';\n\n/**\n * Preset configurations for common repair operations\n */\nexport const PRESETS: Record<PresetName, Required<RepairOptions>> = {\n  /**\n   * Minimal repair - just remove duplicates and degenerate geometry\n   * Best for cleaning up already-good models\n   */\n  minimal: {\n    removeDuplicateVertex: true,\n    removeDuplicateFace: true,\n    removeUnreferencedVertex: true,\n    removeDegenerateFace: true,\n    fillHoles: false,\n    maxHoleSize: 100,\n    removeNonManifoldFace: false,\n    removeNonManifoldVertex: false,\n    fixNormalOrientation: false,\n    flipNormalsOutside: false,\n    removeTVertexByFlip: false,\n    removeFaceFoldByFlip: false,\n    binaryOutput: true,\n  },\n\n  /**\n   * Print-ready - recommended for 3D printing\n   * Fills holes and fixes normals for watertight manifold output\n   */\n  'print-ready': {\n    removeDuplicateVertex: true,\n    removeDuplicateFace: true,\n    removeUnreferencedVertex: true,\n    removeDegenerateFace: true,\n    fillHoles: true,\n    maxHoleSize: 100,\n    removeNonManifoldFace: false,\n    removeNonManifoldVertex: false,\n    fixNormalOrientation: true,\n    flipNormalsOutside: true,\n    removeTVertexByFlip: false,\n    removeFaceFoldByFlip: false,\n    binaryOutput: true,\n  },\n\n  /**\n   * Aggressive - all repairs enabled\n   * Use when other presets fail to produce a valid mesh\n   */\n  aggressive: {\n    removeDuplicateVertex: true,\n    removeDuplicateFace: true,\n    removeUnreferencedVertex: true,\n    removeDegenerateFace: true,\n    fillHoles: true,\n    maxHoleSize: 200,\n    removeNonManifoldFace: true,\n    removeNonManifoldVertex: true,\n    fixNormalOrientation: true,\n    flipNormalsOutside: true,\n    removeTVertexByFlip: true,\n    removeFaceFoldByFlip: true,\n    binaryOutput: true,\n  },\n};\n\n/**\n * Resolve options - merge preset with custom options\n */\nexport function resolveOptions(options?: RepairOptions | PresetName): Required<RepairOptions> {\n  if (!options) {\n    return PRESETS['minimal'];\n  }\n\n  if (typeof options === 'string') {\n    return PRESETS[options];\n  }\n\n  // Merge with minimal preset for defaults\n  return {\n    ...PRESETS['minimal'],\n    ...options,\n  };\n}\n","/**\n * MeshRepair - WebAssembly STL Mesh Repair Library\n *\n * Main TypeScript wrapper class\n *\n * SPDX-License-Identifier: GPL-3.0\n */\n\nimport type {\n  RepairOptions,\n  RepairResult,\n  RepairFileOptions,\n  ProgressCallback,\n  PresetName,\n  MeshRepairModule,\n  EmscriptenFS,\n  InitOptions,\n  MeshRepairLoader,\n} from './types';\nimport { resolveOptions } from './presets';\n\n// Re-export types and presets\nexport * from './types';\nexport { PRESETS } from './presets';\n\n/**\n * MeshRepair - WebAssembly STL Mesh Repair Library\n *\n * A lightweight, headless port of VCGlib for automated repair\n * and sanitization of STL files in the browser.\n *\n * @example\n * ```typescript\n * import { MeshRepair } from '@goodtools/meshrepair';\n * import loadMeshRepair from '@goodtools/meshrepair/wasm';\n *\n * const meshrepair = await MeshRepair.init(loadMeshRepair);\n * const { result, output } = meshrepair.repair('model.stl', stlData, 'print-ready');\n * console.log(`Repaired: ${result.holesFilled} holes filled`);\n * ```\n */\nexport class MeshRepair {\n  /** Direct access to Emscripten virtual filesystem */\n  public readonly FS: EmscriptenFS;\n\n  private lib: MeshRepairModule;\n  private uploadDir = '/uploads';\n  private outputDir = '/output';\n\n  /**\n   * Initialize MeshRepair WASM module\n   *\n   * @param loader - Function that loads the WASM module (import from '@goodtools/meshrepair/wasm')\n   * @param options - Initialization options\n   * @returns Promise resolving to MeshRepair instance\n   *\n   * @example\n   * ```typescript\n   * import { MeshRepair } from '@goodtools/meshrepair';\n   * import loadMeshRepair from '@goodtools/meshrepair/wasm';\n   *\n   * const meshrepair = await MeshRepair.init(loadMeshRepair);\n   *\n   * // With custom WASM location\n   * const meshrepair = await MeshRepair.init(loadMeshRepair, {\n   *   locateFile: (path) => `/assets/${path}`\n   * });\n   * ```\n   */\n  static async init(loader: MeshRepairLoader, options?: InitOptions): Promise<MeshRepair> {\n    const lib = await loader(options);\n    return new MeshRepair(lib);\n  }\n\n  private constructor(lib: MeshRepairModule) {\n    this.lib = lib;\n    this.FS = lib.FS;\n\n    // Create working directories\n    try {\n      this.lib.FS.mkdir(this.uploadDir);\n    } catch {\n      // Directory may already exist\n    }\n    try {\n      this.lib.FS.mkdir(this.outputDir);\n    } catch {\n      // Directory may already exist\n    }\n  }\n\n  /**\n   * Repair an STL file by passing data directly\n   *\n   * Convenience method for smaller files. For large files,\n   * use `FS.writeFile()` followed by `repairFile()`.\n   *\n   * @param name - Filename (used for virtual FS path)\n   * @param data - STL file data\n   * @param options - Repair options or preset name\n   * @param onProgress - Optional progress callback\n   * @returns Repair result and output buffer\n   *\n   * @example\n   * ```typescript\n   * const stlData = await fetch('/model.stl').then(r => r.arrayBuffer());\n   * const { result, output } = meshrepair.repair('model.stl', new Uint8Array(stlData), 'print-ready');\n   * ```\n   */\n  repair(\n    name: string,\n    data: string | ArrayBufferView,\n    options?: RepairOptions | PresetName,\n    onProgress?: ProgressCallback\n  ): { result: RepairResult; output: Uint8Array } {\n    const inputPath = `${this.uploadDir}/${name}`;\n    this.lib.FS.writeFile(inputPath, data);\n\n    try {\n      const response = this.repairFile(inputPath, {\n        options,\n        onProgress,\n      });\n      return { result: response.result, output: response.output };\n    } finally {\n      // Cleanup input file\n      try {\n        this.lib.FS.unlink(inputPath);\n      } catch {\n        // Ignore cleanup errors\n      }\n    }\n  }\n\n  /**\n   * Repair an STL file from a path in the virtual filesystem\n   *\n   * Use this for large files - write with `FS.writeFile()` first.\n   *\n   * @param inputPath - Path to STL file in virtual FS\n   * @param options - Repair options\n   * @returns Repair result, output buffer, and output path\n   *\n   * @example\n   * ```typescript\n   * // Write large file directly to FS\n   * meshrepair.FS.writeFile('/uploads/huge.stl', hugeBuffer);\n   *\n   * // Repair by path\n   * const { result, output } = meshrepair.repairFile('/uploads/huge.stl', {\n   *   options: 'print-ready',\n   *   onProgress: (step, p) => console.log(`${step}: ${p * 100}%`)\n   * });\n   * ```\n   */\n  repairFile(\n    inputPath: string,\n    options?: RepairFileOptions\n  ): { result: RepairResult; output: Uint8Array; outputPath: string } {\n    const opts = options ?? {};\n    const finalOutputPath = opts.outputPath ?? this.generateOutputPath(inputPath);\n    const mergedOptions = resolveOptions(opts.options);\n\n    const session = new this.lib.RepairSession(inputPath);\n\n    try {\n      // WASM binding requires a callback function, use no-op if not provided\n      const callback = opts.onProgress ?? (() => {});\n      const result = session.repair(mergedOptions, finalOutputPath, callback);\n\n      if (result.code !== 0) {\n        throw new Error(result.error || `Repair failed with code ${result.code}`);\n      }\n\n      const output = this.lib.FS.readFile(finalOutputPath);\n      return { result, output, outputPath: finalOutputPath };\n    } finally {\n      session.delete();\n    }\n  }\n\n  /**\n   * Repair an STL file without reading output back to JavaScript\n   *\n   * Memory-efficient for large files or when chaining operations.\n   * The output file remains in the virtual FS.\n   *\n   * @param inputPath - Path to STL file in virtual FS\n   * @param options - Repair options\n   * @returns Repair result and output path\n   *\n   * @example\n   * ```typescript\n   * meshrepair.FS.writeFile('/uploads/huge.stl', hugeBuffer);\n   *\n   * const { result, outputPath } = meshrepair.repairFileInPlace('/uploads/huge.stl', {\n   *   options: 'aggressive'\n   * });\n   *\n   * // Read output when needed\n   * const repairedData = meshrepair.FS.readFile(outputPath);\n   * ```\n   */\n  repairFileInPlace(\n    inputPath: string,\n    options?: RepairFileOptions\n  ): { result: RepairResult; outputPath: string } {\n    const opts = options ?? {};\n    const finalOutputPath = opts.outputPath ?? this.generateOutputPath(inputPath);\n    const mergedOptions = resolveOptions(opts.options);\n\n    const session = new this.lib.RepairSession(inputPath);\n\n    try {\n      // WASM binding requires a callback function, use no-op if not provided\n      const callback = opts.onProgress ?? (() => {});\n      const result = session.repair(mergedOptions, finalOutputPath, callback);\n\n      if (result.code !== 0) {\n        throw new Error(result.error || `Repair failed with code ${result.code}`);\n      }\n\n      return { result, outputPath: finalOutputPath };\n    } finally {\n      session.delete();\n    }\n  }\n\n  /**\n   * Clean up resources and remove working directories\n   */\n  destroy(): void {\n    try {\n      this.removeDir(this.uploadDir);\n    } catch {\n      // Ignore cleanup errors\n    }\n    try {\n      this.removeDir(this.outputDir);\n    } catch {\n      // Ignore cleanup errors\n    }\n  }\n\n  /**\n   * Generate output path from input path\n   */\n  private generateOutputPath(inputPath: string): string {\n    const basename = inputPath.split('/').pop() || 'output';\n    const name = basename.replace(/\\.stl$/i, '');\n    return `${this.outputDir}/${name}_repaired.stl`;\n  }\n\n  /**\n   * Recursively remove a directory\n   */\n  private removeDir(path: string): void {\n    const entries = this.lib.FS.readdir(path);\n    for (const entry of entries) {\n      if (entry === '.' || entry === '..') continue;\n      const fullPath = `${path}/${entry}`;\n      const stat = this.lib.FS.stat(fullPath);\n      if (this.lib.FS.isDir(stat.mode)) {\n        this.removeDir(fullPath);\n      } else {\n        this.lib.FS.unlink(fullPath);\n      }\n    }\n    this.lib.FS.rmdir(path);\n  }\n}\n\nexport default MeshRepair;\n"],"names":[],"mappings":"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"}