partforge 0.67.1 → 0.67.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "partforge",
3
- "version": "0.67.1",
3
+ "version": "0.67.2",
4
4
  "description": "Turn a declarative part definition into a parametric-CAD web app (three.js + Manifold/Replicad). Requires a Vite-based consumer.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -12,16 +12,11 @@
12
12
  // capability (Manifold can't do toSTEP; both backends now define shape2d, so
13
13
  // that stub is dead in practice — kept as a safety net for a future backend).
14
14
  // The per-Solid twin of this layer is addSugar() in solid-sugar.js.
15
- // opentype.js 2.x ships no `exports` map: bundlers take its `module` field (real
16
- // ESM, named `parse`), while Node ESM takes `main` (a UMD/CJS bundle, whose named
17
- // exports Node cannot statically detect — the namespace holds only `default`).
18
- // So `import * as opentype` gives a working `.parse` in the browser and `undefined`
19
- // under Node, which broke every headless text2d build (`opentype.parse is not a
20
- // function`) while the browser stayed green. Normalize both interop shapes here.
15
+ // opentype.js's namespace shape differs between bundler and Node resolution
16
+ // see opentype-interop.js for the trap (it has bitten once in each direction).
21
17
  import * as opentypeNamespace from "opentype.js";
22
- const opentype = typeof opentypeNamespace.parse === "function"
23
- ? opentypeNamespace
24
- : (opentypeNamespace.default ?? opentypeNamespace);
18
+ import { normalizeOpentype } from "./opentype-interop.js";
19
+ const opentype = normalizeOpentype(opentypeNamespace);
25
20
  import { KernelCapabilityError } from "./errors.js";
26
21
  import { isPlainOptions, KERNEL_OP_SPECS } from "./op-options.js";
27
22
  import { textGlyphs } from "./text2d.js";
@@ -0,0 +1,13 @@
1
+ // opentype.js 2.x ships no `exports` map, so what importing it yields splits by
2
+ // resolver: bundlers take the `module` field (real ESM — named `parse`, NO
3
+ // default export), while Node takes `main` (a UMD/CJS bundle whose named exports
4
+ // Node's lexer cannot statically detect — the namespace holds ONLY `default`).
5
+ // Reading `.default` unconditionally is therefore correct under Node and
6
+ // `undefined` in every browser bundle; reading a named export is the reverse.
7
+ // That asymmetry once broke headless text2d builds (kernel-front's static
8
+ // import) and later broke every BROWSER build of a part declaring `fonts`
9
+ // ("undefined is not an object (evaluating 'p.parse')") while headless tests
10
+ // stayed green (jobs' dynamic import). Both call sites normalize through this
11
+ // one function so the two interop shapes stay handled in one place.
12
+ export const normalizeOpentype = (ns) =>
13
+ typeof ns?.parse === "function" ? ns : (ns?.default ?? ns);
@@ -5,6 +5,7 @@
5
5
  import { meshTo3MF } from "./geometry/threemf.js";
6
6
  import { exportablePartNames } from "./export-select.js";
7
7
  import { resolveFonts } from "./fonts.js";
8
+ import { normalizeOpentype } from "./geometry/opentype-interop.js";
8
9
  import { ensureImports, resolveImports } from "./imports.js";
9
10
  import { safeName } from "./safe-name.js";
10
11
  import { exportSubParts, resolveParams, buildPosed } from "./part-model.js";
@@ -100,9 +101,11 @@ export async function handle(kernel, part, msg, post, opts = {}) {
100
101
  try {
101
102
  // Preload any part-declared fonts into the kernel before building — once per
102
103
  // font name; a lazy dynamic import because this is async context (unlike the
103
- // synchronous kernel-front), so it doesn't cost sync callers anything.
104
+ // synchronous kernel-front), so it doesn't cost sync callers anything. The
105
+ // namespace shape differs between bundler and Node resolution (a bare
106
+ // `.default` here is undefined in every browser bundle) — normalize it.
104
107
  if (part.fonts && kernel._fonts) {
105
- const opentype = (await import("opentype.js")).default;
108
+ const opentype = normalizeOpentype(await import("opentype.js"));
106
109
  const bufs = await resolveFonts(part.fonts);
107
110
  for (const [name, buf] of bufs) if (!kernel._fonts.has(name)) kernel._fonts.set(name, opentype.parse(buf));
108
111
  }
@@ -4,6 +4,7 @@
4
4
  import Module from "manifold-3d";
5
5
  import { createManifoldKernel } from "../framework/geometry/manifold-backend.js";
6
6
  import { resolveFonts } from "../framework/fonts.js";
7
+ import { normalizeOpentype } from "../framework/geometry/opentype-interop.js";
7
8
  import { ensureImports } from "../framework/imports.js";
8
9
  import { nodeAssetSources } from "./assets.js";
9
10
  import { tessellateStepAssets } from "./step-mesh.js";
@@ -12,7 +13,7 @@ export async function bootManifoldKernel({ quality = "preview", fonts, imports,
12
13
  const wasm = await Module();
13
14
  wasm.setup();
14
15
  const kernel = createManifoldKernel(wasm, { quality });
15
- if (fonts) { const opentype = (await import("opentype.js")).default;
16
+ if (fonts) { const opentype = normalizeOpentype(await import("opentype.js"));
16
17
  for (const [name, buf] of await resolveFonts(nodeAssetSources(fonts))) kernel._fonts.set(name, opentype.parse(buf)); }
17
18
  if (imports) {
18
19
  const decl = nodeAssetSources(imports);
@@ -6,6 +6,7 @@ import path from "path";
6
6
  import fs from "fs";
7
7
  import { createOcctKernel } from "../framework/geometry/occt-backend.js";
8
8
  import { resolveFonts } from "../framework/fonts.js";
9
+ import { normalizeOpentype } from "../framework/geometry/opentype-interop.js";
9
10
  import { ensureImports } from "../framework/imports.js";
10
11
  import { nodeAssetSources } from "./assets.js";
11
12
 
@@ -18,7 +19,7 @@ export async function bootOcctKernel({ fonts, imports, importMeshes } = {}) {
18
19
  const replicad = await import("replicad");
19
20
  replicad.setOC(OC);
20
21
  const kernel = createOcctKernel(replicad);
21
- if (fonts) { const opentype = (await import("opentype.js")).default;
22
+ if (fonts) { const opentype = normalizeOpentype(await import("opentype.js"));
22
23
  for (const [name, buf] of await resolveFonts(nodeAssetSources(fonts))) kernel._fonts.set(name, opentype.parse(buf)); }
23
24
  if (imports) await ensureImports(kernel, nodeAssetSources(imports), importMeshes ?? null);
24
25
  return kernel;