Skip to main content

InvariantCAD 0.2.0

InvariantCAD 0.2.0 adds one public exact-import workflow and makes the 0.1 foundation strict and predictable. Builders now check their inputs when each method is called. Parsing, the CLI, and signal-bearing evaluation bound untrusted documents, options, and files before using them. Kernels report only measurements they can stand behind. Public document authoring remains Document v6. Imported-body documents use a fixed Document v7 subset, read and evaluated only by the imported-body functions. This release contains breaking changes for some 0.1.1 callers. Read the upgrade notes before upgrading.

Highlights

  • Verified single-body import.
    • createImportedBodyDocument, stringifyImportedBodyDocument, parseImportedBodyDocument, and Evaluator.evaluateImportedBody persist and evaluate one exact solid backed by a SHA-256 byte commitment.
    • Bytes come from a caller callback and are verified before use. The workflow never falls back to weak native import or to a mesh conversion.
  • Author-time checks.
    • Builder methods validate option values, ownership, and ceilings when they are called, and read caller records once through their own data properties.
    • build() returns a detached, deeply frozen document that satisfies the strict document grammar.
    • SketchBuilder.regularPolygon(...) now works.
  • Hardened untrusted input.
    • parseDocument rejects duplicate JSON member names.
    • Serialization and the CLI are bounded.
    • Diagnostic paths are RFC 6901 JSON Pointers that escape every document key.
    • The CLI fails closed on bad arguments and escapes document text.
    • An evaluation with a signal snapshots its request, then yields to the host so aborts from timers, UI handlers, and workers take effect.
  • Correct, bounded evaluation.
    • Assemblies have fixed occurrence, path, and depth ceilings.
    • Mirror normals, revolve axes, sweep miters, and loft phases are checked before kernel work.
    • Custom sketch solvers are held to their declared protocol.
    • Expression evaluation and validation are linear in distinct nodes.
  • Honest kernel results.
    • ShapeMeasurements.genus is number | null, and null means unsupported.
    • Stock OCCT transforms spheres and cones.
    • OCCT mesh() no longer depends on earlier tessellations.
    • STEP export on stock OCCT is bounded, and single-product export is byte-deterministic.
    • Manifold rejects foreign shapes and profiles beyond ±1e10 mm with readable diagnostics.
  • A GitHub-driven release flow.
    • Every change reaches npm through a reviewed release pull request.
    • Publication uses OIDC trusted publishing with npm provenance.
    • The tagged GitHub release and the live documentation follow the published package.

Verified single-body import

createImportedBodyDocument(...) records a caller-owned SHA-256 digest, exact byte length, format and media type, and unit policy without performing I/O. Evaluator.evaluateImportedBody(...) resolves the bytes through a callback. It checks the committed length against the resource ceiling and verifies the digest before the strong exact B-Rep single-solid import runs. STEP uses the file’s units; text and binary BREP use caller-declared units. The saved JSON is a fixed, minimal Document v7 subset: one resource, one importedBody node, and one solid output. Tests pin its canonical bytes and digest, so imported-body documents saved by 0.2.0 stay readable. The general Document v1–v6 APIs reject Document v7. validateDocument, parseDocument, parseDocumentValue, migrateDocument, hashDesignFeatures, analyzeDesignImpact, and Evaluator.evaluate return one IR_INVALID diagnostic that names the imported-body functions. stringifyDocument and cloneDocument throw a TypeError, and hashDocument rejects with one. See verified single-body import.

Strict authoring

  • Plain records and lists. Option records must be plain objects, and the lists and records a document stores must be plain dense arrays and plain objects. Own fields are read once, whether enumerable or not. Accessors never run, and fields inherited from Object.prototype are never read.
  • Ownership. A Parameter from another builder, a handle created with an exported constructor, or a builder used after its callback returned now throws.
  • Ceilings. Metadata, topology selections, option records, and raw expression IR have fixed size and depth ceilings. They are refused before their contents are copied.
See programmer errors for the complete list.

Untrusted input and diagnostics

Parsing, serialization, the CLI, and evaluation with a signal now apply their documented ceilings before they allocate the data those ceilings protect. An evaluation without a signal reads the supplied document directly, so pass untrusted values through parseDocument or parseDocumentValue before evaluating them. Every diagnostic path escapes / and ~ in document keys, so a node named a/b is reported at /nodes/a~1b. A non-string outputs entry or configuration option fails with IR_INVALID. See diagnostics and limits.

Kernels and exchange

  • Genus. Manifold reports exact per-component genus. Stock and owned OCCT report null (unsupported) instead of the 0.1.1 Euler-characteristic heuristic.
  • STEP export. On stock OCCT it has output, input, scan, and entity ceilings. Single-product zero-override export is byte-deterministic.
  • Binary STL. Headers fit long multi-byte names on a character boundary, and a name starting with solid is prefixed so readers do not mistake the file for ASCII STL.
  • OCCT runtime. Kernel capabilities are frozen, dispose() releases every remaining native handle, and OCCT measure() counts each occurrence of a solid that a compound repeats.

Public entry points

The five public entry points are unchanged:
  • invariantcad
  • invariantcad/conformance
  • invariantcad/kernels/occt
  • invariantcad/kernels/occt/browser
  • invariantcad/kernels/occt/node

Important boundaries

  • Public document authoring, schemas, migration targets, and aliases remain Document v6. Documents v1–v6 remain frozen and directly supported.
  • The imported-body subset is the only public Document v7 JSON. Resources beyond it, datums, body sets, products, external occurrences, and feature-hash protocol v2 remain staged, repository-only work.
  • The InvariantCAD-owned OCCT facade is not distributed in the npm package. Draft geometry and some exact topology-history guarantees still require it.
  • Mesh and exact behavior remain distinct. Unsupported exact work is never silently converted to an approximate operation.

Upgrade notes

Node.js 22.13 or newer is still required, and existing v1–v6 documents need no migration. Review these changes:
  • Document v7 JSON. Code that passed Document v7 JSON to validateDocument, parseDocument, stringifyDocument, hashDocument, or Evaluator.evaluate must use the imported-body functions instead.
  • Option records and lists. They must be plain object literals and plain arrays. Class instances, getter-backed objects, array subclasses, and sparse arrays now throw TypeError.
  • Genus. ShapeMeasurements.genus can be null; handle it explicitly.
  • Manifold shape ownership. Each ManifoldKernel accepts only the shapes it created.
  • Revolve. A revolve profile that crosses its axis now fails with FEATURE_INVALID instead of being clipped on Manifold.
  • Sweep. It now accounts for the corner miter, so some tight 0.1.1 sweeps need longer segments, gentler corners, or a smaller profile.
  • Custom sketch solvers. They must advertise every entity and constraint kind they accept, and their status is authoritative.
  • Assemblies. Those beyond 100,000 occurrence records, 1,000,000 instance path segments, or depth 64 now fail with RESOURCE_LIMIT_EXCEEDED.
  • CLI export. invariantcad export requires --output for documents with more than one output.
  • Declaration maps. The package no longer ships TypeScript declaration maps; declarations keep their JSDoc.
For the exhaustive change record, see the 0.2.0 changelog. For exact current capabilities and planned work, see the support matrix and roadmap.