partforge 0.33.0 → 0.34.0
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
|
@@ -32,6 +32,41 @@ import { composePose, transformPositions } from "./pose.js";
|
|
|
32
32
|
import { meshToStl } from "./mesh-stl.js";
|
|
33
33
|
const MESH = { preview: { tolerance: 0.1, angularTolerance: 0.5 }, print: { tolerance: 0.01, angularTolerance: 0.1 } };
|
|
34
34
|
|
|
35
|
+
// Run replicad's `exportSTEP` (via `runExport`) and return the STEP bytes as a
|
|
36
|
+
// standalone ArrayBuffer WITHOUT touching a Blob — the sandbox worker on
|
|
37
|
+
// Safari/Firefox cannot read a Blob. replicad writes the STEP text to OCCT's
|
|
38
|
+
// virtual FS and reads it back with oc.FS.readFile; we wrap that read to capture
|
|
39
|
+
// the bytes, then hand them straight back. Two Safari-specific hazards, both
|
|
40
|
+
// handled here:
|
|
41
|
+
// * The captured Uint8Array is a view into the WASM heap, so we copy it
|
|
42
|
+
// immediately (.slice()) — the post-write cleanup can move/free the heap.
|
|
43
|
+
// * On Safari's OCCT build, that cleanup THROWS a destructor-signature
|
|
44
|
+
// mismatch AFTER the file is fully written and read ("...Write Done", then a
|
|
45
|
+
// RuntimeError: rawDestructor). The bytes are already captured, so the export
|
|
46
|
+
// succeeded — swallow the cleanup crash and return them. Only rethrow if
|
|
47
|
+
// nothing was captured (a genuine export failure).
|
|
48
|
+
// Exported for direct unit testing of the crash-tolerance (the fatal path only
|
|
49
|
+
// reproduces in real Safari).
|
|
50
|
+
export function stepBytesViaFsCapture(oc, runExport) {
|
|
51
|
+
const realRead = oc.FS.readFile; // restore this exact ref (no bind accumulation across exports)
|
|
52
|
+
let captured = null;
|
|
53
|
+
oc.FS.readFile = (path, ...rest) => {
|
|
54
|
+
const bytes = realRead.call(oc.FS, path, ...rest);
|
|
55
|
+
if (typeof path === "string" && path.toLowerCase().endsWith(".step")) captured = bytes.slice();
|
|
56
|
+
return bytes;
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
runExport();
|
|
60
|
+
} catch (e) {
|
|
61
|
+
if (!captured) throw e; // failed before producing any STEP bytes — a real error
|
|
62
|
+
// else: post-write cleanup crashed after the file was captured; ignore it.
|
|
63
|
+
} finally {
|
|
64
|
+
oc.FS.readFile = realRead;
|
|
65
|
+
}
|
|
66
|
+
if (!captured || captured.byteLength === 0) throw new Error("STEP export produced no bytes");
|
|
67
|
+
return captured.buffer;
|
|
68
|
+
}
|
|
69
|
+
|
|
35
70
|
export function createOcctKernel(replicad) {
|
|
36
71
|
const { makeCylinder, makeBox, makeCircle, makeHelix, assembleWire, genericSweep,
|
|
37
72
|
makeCompound, loft, draw, exportSTEP, measureVolume, makeSphere, makeLine, Plane, getOC } = replicad;
|
|
@@ -449,28 +484,9 @@ export function createOcctKernel(replicad) {
|
|
|
449
484
|
});
|
|
450
485
|
},
|
|
451
486
|
shape2d,
|
|
452
|
-
toSTEP: (named) =>
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
// cannot read a Blob, so we intercept the FS read to capture the raw
|
|
456
|
-
// Uint8Array before it is wrapped, and return an ArrayBuffer instead. The
|
|
457
|
-
// interception is synchronous (exportSTEP is sync) and restored in finally.
|
|
458
|
-
const oc = getOC();
|
|
459
|
-
const realRead = oc.FS.readFile.bind(oc.FS);
|
|
460
|
-
let captured = null;
|
|
461
|
-
oc.FS.readFile = (path, ...rest) => {
|
|
462
|
-
const bytes = realRead(path, ...rest);
|
|
463
|
-
if (typeof path === "string" && path.toLowerCase().endsWith(".step")) captured = bytes;
|
|
464
|
-
return bytes;
|
|
465
|
-
};
|
|
466
|
-
try {
|
|
467
|
-
exportSTEP(named.map(({ name, solid }) => ({ name, shape: solid._mat()._s })));
|
|
468
|
-
} finally {
|
|
469
|
-
oc.FS.readFile = realRead;
|
|
470
|
-
}
|
|
471
|
-
if (!captured) throw new Error("STEP export produced no bytes");
|
|
472
|
-
return Promise.resolve(captured.buffer.slice(captured.byteOffset, captured.byteOffset + captured.byteLength));
|
|
473
|
-
},
|
|
487
|
+
toSTEP: (named) =>
|
|
488
|
+
Promise.resolve(stepBytesViaFsCapture(getOC(), () =>
|
|
489
|
+
exportSTEP(named.map(({ name, solid }) => ({ name, shape: solid._mat()._s }))))),
|
|
474
490
|
beginSubPart: (name) => cache.begin(name),
|
|
475
491
|
endSubPart: () => cache.end(),
|
|
476
492
|
sweepCache: () => cache.sweep(),
|