brep-io-kernel 1.0.0-ci.9

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.
Files changed (271) hide show
  1. package/LICENSE.md +32 -0
  2. package/README.md +154 -0
  3. package/dist-kernel/brep-kernel.js +74699 -0
  4. package/package.json +58 -0
  5. package/src/BREP/AssemblyComponent.js +42 -0
  6. package/src/BREP/BREP.js +43 -0
  7. package/src/BREP/BetterSolid.js +805 -0
  8. package/src/BREP/Edge.js +103 -0
  9. package/src/BREP/Extrude.js +403 -0
  10. package/src/BREP/Face.js +187 -0
  11. package/src/BREP/MeshRepairer.js +634 -0
  12. package/src/BREP/OffsetShellSolid.js +614 -0
  13. package/src/BREP/PointCloudWrap.js +302 -0
  14. package/src/BREP/Revolve.js +345 -0
  15. package/src/BREP/SolidMethods/authoring.js +112 -0
  16. package/src/BREP/SolidMethods/booleanOps.js +230 -0
  17. package/src/BREP/SolidMethods/chamfer.js +122 -0
  18. package/src/BREP/SolidMethods/edgeResolution.js +25 -0
  19. package/src/BREP/SolidMethods/fillet.js +792 -0
  20. package/src/BREP/SolidMethods/index.js +72 -0
  21. package/src/BREP/SolidMethods/io.js +105 -0
  22. package/src/BREP/SolidMethods/lifecycle.js +103 -0
  23. package/src/BREP/SolidMethods/manifoldOps.js +375 -0
  24. package/src/BREP/SolidMethods/meshCleanup.js +2512 -0
  25. package/src/BREP/SolidMethods/meshQueries.js +264 -0
  26. package/src/BREP/SolidMethods/metadata.js +106 -0
  27. package/src/BREP/SolidMethods/metrics.js +51 -0
  28. package/src/BREP/SolidMethods/transforms.js +361 -0
  29. package/src/BREP/SolidMethods/visualize.js +508 -0
  30. package/src/BREP/SolidShared.js +26 -0
  31. package/src/BREP/Sweep.js +1596 -0
  32. package/src/BREP/Tube.js +857 -0
  33. package/src/BREP/Vertex.js +43 -0
  34. package/src/BREP/applyBooleanOperation.js +704 -0
  35. package/src/BREP/boundsUtils.js +48 -0
  36. package/src/BREP/chamfer.js +551 -0
  37. package/src/BREP/edgePolylineUtils.js +85 -0
  38. package/src/BREP/fillets/common.js +388 -0
  39. package/src/BREP/fillets/fillet.js +1422 -0
  40. package/src/BREP/fillets/filletGeometry.js +15 -0
  41. package/src/BREP/fillets/inset.js +389 -0
  42. package/src/BREP/fillets/offsetHelper.js +143 -0
  43. package/src/BREP/fillets/outset.js +88 -0
  44. package/src/BREP/helix.js +193 -0
  45. package/src/BREP/meshToBrep.js +234 -0
  46. package/src/BREP/primitives.js +279 -0
  47. package/src/BREP/setupManifold.js +71 -0
  48. package/src/BREP/threadGeometry.js +1120 -0
  49. package/src/BREP/triangleUtils.js +8 -0
  50. package/src/BREP/triangulate.js +608 -0
  51. package/src/FeatureRegistry.js +183 -0
  52. package/src/PartHistory.js +1132 -0
  53. package/src/UI/AccordionWidget.js +292 -0
  54. package/src/UI/CADmaterials.js +850 -0
  55. package/src/UI/EnvMonacoEditor.js +522 -0
  56. package/src/UI/FloatingWindow.js +396 -0
  57. package/src/UI/HistoryWidget.js +457 -0
  58. package/src/UI/MainToolbar.js +131 -0
  59. package/src/UI/ModelLibraryView.js +194 -0
  60. package/src/UI/OrthoCameraIdle.js +206 -0
  61. package/src/UI/PluginsWidget.js +280 -0
  62. package/src/UI/SceneListing.js +606 -0
  63. package/src/UI/SelectionFilter.js +629 -0
  64. package/src/UI/ViewCube.js +389 -0
  65. package/src/UI/assembly/AssemblyConstraintCollectionWidget.js +329 -0
  66. package/src/UI/assembly/AssemblyConstraintControlsWidget.js +282 -0
  67. package/src/UI/assembly/AssemblyConstraintsWidget.css +292 -0
  68. package/src/UI/assembly/AssemblyConstraintsWidget.js +1373 -0
  69. package/src/UI/assembly/constraintFaceUtils.js +115 -0
  70. package/src/UI/assembly/constraintHighlightUtils.js +70 -0
  71. package/src/UI/assembly/constraintLabelUtils.js +31 -0
  72. package/src/UI/assembly/constraintPointUtils.js +64 -0
  73. package/src/UI/assembly/constraintSelectionUtils.js +185 -0
  74. package/src/UI/assembly/constraintStatusUtils.js +142 -0
  75. package/src/UI/componentSelectorModal.js +240 -0
  76. package/src/UI/controls/CombinedTransformControls.js +386 -0
  77. package/src/UI/dialogs.js +351 -0
  78. package/src/UI/expressionsManager.js +100 -0
  79. package/src/UI/featureDialogWidgets/booleanField.js +25 -0
  80. package/src/UI/featureDialogWidgets/booleanOperationField.js +97 -0
  81. package/src/UI/featureDialogWidgets/buttonField.js +45 -0
  82. package/src/UI/featureDialogWidgets/componentSelectorField.js +102 -0
  83. package/src/UI/featureDialogWidgets/defaultField.js +23 -0
  84. package/src/UI/featureDialogWidgets/fileField.js +66 -0
  85. package/src/UI/featureDialogWidgets/index.js +34 -0
  86. package/src/UI/featureDialogWidgets/numberField.js +165 -0
  87. package/src/UI/featureDialogWidgets/optionsField.js +33 -0
  88. package/src/UI/featureDialogWidgets/referenceSelectionField.js +208 -0
  89. package/src/UI/featureDialogWidgets/stringField.js +24 -0
  90. package/src/UI/featureDialogWidgets/textareaField.js +28 -0
  91. package/src/UI/featureDialogWidgets/threadDesignationField.js +160 -0
  92. package/src/UI/featureDialogWidgets/transformField.js +252 -0
  93. package/src/UI/featureDialogWidgets/utils.js +43 -0
  94. package/src/UI/featureDialogWidgets/vec3Field.js +133 -0
  95. package/src/UI/featureDialogs.js +1414 -0
  96. package/src/UI/fileManagerWidget.js +615 -0
  97. package/src/UI/history/HistoryCollectionWidget.js +1294 -0
  98. package/src/UI/history/historyCollectionWidget.css.js +257 -0
  99. package/src/UI/history/historyDisplayInfo.js +133 -0
  100. package/src/UI/mobile.js +28 -0
  101. package/src/UI/objectDump.js +442 -0
  102. package/src/UI/pmi/AnnotationCollectionWidget.js +120 -0
  103. package/src/UI/pmi/AnnotationHistory.js +353 -0
  104. package/src/UI/pmi/AnnotationRegistry.js +90 -0
  105. package/src/UI/pmi/BaseAnnotation.js +269 -0
  106. package/src/UI/pmi/LabelOverlay.css +102 -0
  107. package/src/UI/pmi/LabelOverlay.js +191 -0
  108. package/src/UI/pmi/PMIMode.js +1550 -0
  109. package/src/UI/pmi/PMIViewsWidget.js +1098 -0
  110. package/src/UI/pmi/annUtils.js +729 -0
  111. package/src/UI/pmi/dimensions/AngleDimensionAnnotation.js +647 -0
  112. package/src/UI/pmi/dimensions/ExplodeBodyAnnotation.js +507 -0
  113. package/src/UI/pmi/dimensions/HoleCalloutAnnotation.js +462 -0
  114. package/src/UI/pmi/dimensions/LeaderAnnotation.js +403 -0
  115. package/src/UI/pmi/dimensions/LinearDimensionAnnotation.js +532 -0
  116. package/src/UI/pmi/dimensions/NoteAnnotation.js +110 -0
  117. package/src/UI/pmi/dimensions/RadialDimensionAnnotation.js +659 -0
  118. package/src/UI/pmi/pmiStyle.js +44 -0
  119. package/src/UI/sketcher/SketchMode3D.js +4095 -0
  120. package/src/UI/sketcher/dimensions.js +674 -0
  121. package/src/UI/sketcher/glyphs.js +236 -0
  122. package/src/UI/sketcher/highlights.js +60 -0
  123. package/src/UI/toolbarButtons/aboutButton.js +5 -0
  124. package/src/UI/toolbarButtons/exportButton.js +609 -0
  125. package/src/UI/toolbarButtons/flatPatternButton.js +307 -0
  126. package/src/UI/toolbarButtons/importButton.js +160 -0
  127. package/src/UI/toolbarButtons/inspectorToggleButton.js +12 -0
  128. package/src/UI/toolbarButtons/metadataButton.js +1063 -0
  129. package/src/UI/toolbarButtons/orientToFaceButton.js +114 -0
  130. package/src/UI/toolbarButtons/registerDefaultButtons.js +46 -0
  131. package/src/UI/toolbarButtons/saveButton.js +99 -0
  132. package/src/UI/toolbarButtons/scriptRunnerButton.js +302 -0
  133. package/src/UI/toolbarButtons/testsButton.js +26 -0
  134. package/src/UI/toolbarButtons/undoRedoButtons.js +25 -0
  135. package/src/UI/toolbarButtons/wireframeToggleButton.js +5 -0
  136. package/src/UI/toolbarButtons/zoomToFitButton.js +5 -0
  137. package/src/UI/triangleDebuggerWindow.js +945 -0
  138. package/src/UI/viewer.js +4228 -0
  139. package/src/assemblyConstraints/AssemblyConstraintHistory.js +1576 -0
  140. package/src/assemblyConstraints/AssemblyConstraintRegistry.js +120 -0
  141. package/src/assemblyConstraints/BaseAssemblyConstraint.js +66 -0
  142. package/src/assemblyConstraints/constraintExpressionUtils.js +35 -0
  143. package/src/assemblyConstraints/constraintUtils/parallelAlignment.js +676 -0
  144. package/src/assemblyConstraints/constraints/AngleConstraint.js +485 -0
  145. package/src/assemblyConstraints/constraints/CoincidentConstraint.js +194 -0
  146. package/src/assemblyConstraints/constraints/DistanceConstraint.js +616 -0
  147. package/src/assemblyConstraints/constraints/FixedConstraint.js +78 -0
  148. package/src/assemblyConstraints/constraints/ParallelConstraint.js +252 -0
  149. package/src/assemblyConstraints/constraints/TouchAlignConstraint.js +961 -0
  150. package/src/core/entities/HistoryCollectionBase.js +72 -0
  151. package/src/core/entities/ListEntityBase.js +109 -0
  152. package/src/core/entities/schemaProcesser.js +121 -0
  153. package/src/exporters/sheetMetalFlatPattern.js +659 -0
  154. package/src/exporters/sheetMetalUnfold.js +862 -0
  155. package/src/exporters/step.js +1135 -0
  156. package/src/exporters/threeMF.js +575 -0
  157. package/src/features/assemblyComponent/AssemblyComponentFeature.js +780 -0
  158. package/src/features/boolean/BooleanFeature.js +94 -0
  159. package/src/features/chamfer/ChamferFeature.js +116 -0
  160. package/src/features/datium/DatiumFeature.js +80 -0
  161. package/src/features/edgeFeatureUtils.js +41 -0
  162. package/src/features/extrude/ExtrudeFeature.js +143 -0
  163. package/src/features/fillet/FilletFeature.js +197 -0
  164. package/src/features/helix/HelixFeature.js +405 -0
  165. package/src/features/hole/HoleFeature.js +1050 -0
  166. package/src/features/hole/screwClearance.js +86 -0
  167. package/src/features/hole/threadDesignationCatalog.js +149 -0
  168. package/src/features/imageHeightSolid/ImageHeightmapSolidFeature.js +463 -0
  169. package/src/features/imageToFace/ImageToFaceFeature.js +727 -0
  170. package/src/features/imageToFace/imageEditor.js +1270 -0
  171. package/src/features/imageToFace/traceUtils.js +971 -0
  172. package/src/features/import3dModel/Import3dModelFeature.js +151 -0
  173. package/src/features/loft/LoftFeature.js +605 -0
  174. package/src/features/mirror/MirrorFeature.js +151 -0
  175. package/src/features/offsetFace/OffsetFaceFeature.js +370 -0
  176. package/src/features/offsetShell/OffsetShellFeature.js +89 -0
  177. package/src/features/overlapCleanup/OverlapCleanupFeature.js +85 -0
  178. package/src/features/pattern/PatternFeature.js +275 -0
  179. package/src/features/patternLinear/PatternLinearFeature.js +120 -0
  180. package/src/features/patternRadial/PatternRadialFeature.js +186 -0
  181. package/src/features/plane/PlaneFeature.js +154 -0
  182. package/src/features/primitiveCone/primitiveConeFeature.js +99 -0
  183. package/src/features/primitiveCube/primitiveCubeFeature.js +70 -0
  184. package/src/features/primitiveCylinder/primitiveCylinderFeature.js +91 -0
  185. package/src/features/primitivePyramid/primitivePyramidFeature.js +72 -0
  186. package/src/features/primitiveSphere/primitiveSphereFeature.js +62 -0
  187. package/src/features/primitiveTorus/primitiveTorusFeature.js +109 -0
  188. package/src/features/remesh/RemeshFeature.js +97 -0
  189. package/src/features/revolve/RevolveFeature.js +111 -0
  190. package/src/features/selectionUtils.js +118 -0
  191. package/src/features/sheetMetal/SheetMetalContourFlangeFeature.js +1656 -0
  192. package/src/features/sheetMetal/SheetMetalCutoutFeature.js +1056 -0
  193. package/src/features/sheetMetal/SheetMetalFlangeFeature.js +1568 -0
  194. package/src/features/sheetMetal/SheetMetalHemFeature.js +43 -0
  195. package/src/features/sheetMetal/SheetMetalObject.js +141 -0
  196. package/src/features/sheetMetal/SheetMetalTabFeature.js +176 -0
  197. package/src/features/sheetMetal/UNFOLD_NEUTRAL_REQUIREMENTS.md +153 -0
  198. package/src/features/sheetMetal/contour-flange-rebuild-spec.md +261 -0
  199. package/src/features/sheetMetal/profileUtils.js +25 -0
  200. package/src/features/sheetMetal/sheetMetalCleanup.js +9 -0
  201. package/src/features/sheetMetal/sheetMetalFaceTypes.js +146 -0
  202. package/src/features/sheetMetal/sheetMetalMetadata.js +165 -0
  203. package/src/features/sheetMetal/sheetMetalPipeline.js +169 -0
  204. package/src/features/sheetMetal/sheetMetalProfileUtils.js +216 -0
  205. package/src/features/sheetMetal/sheetMetalTabUtils.js +29 -0
  206. package/src/features/sheetMetal/sheetMetalTree.js +210 -0
  207. package/src/features/sketch/SketchFeature.js +955 -0
  208. package/src/features/sketch/sketchSolver2D/ConstraintEngine.js +800 -0
  209. package/src/features/sketch/sketchSolver2D/constraintDefinitions.js +704 -0
  210. package/src/features/sketch/sketchSolver2D/mathHelpersMod.js +307 -0
  211. package/src/features/spline/SplineEditorSession.js +988 -0
  212. package/src/features/spline/SplineFeature.js +1388 -0
  213. package/src/features/spline/splineUtils.js +218 -0
  214. package/src/features/sweep/SweepFeature.js +110 -0
  215. package/src/features/transform/TransformFeature.js +152 -0
  216. package/src/features/tube/TubeFeature.js +635 -0
  217. package/src/fs.proxy.js +625 -0
  218. package/src/idbStorage.js +254 -0
  219. package/src/index.js +12 -0
  220. package/src/main.js +15 -0
  221. package/src/metadataManager.js +64 -0
  222. package/src/path.proxy.js +277 -0
  223. package/src/plugins/ghLoader.worker.js +151 -0
  224. package/src/plugins/pluginManager.js +286 -0
  225. package/src/pmi/PMIViewsManager.js +134 -0
  226. package/src/services/componentLibrary.js +198 -0
  227. package/src/tests/ConsoleCapture.js +189 -0
  228. package/src/tests/S7-diagnostics-2025-12-23T18-37-23-570Z.json +630 -0
  229. package/src/tests/browserTests.js +597 -0
  230. package/src/tests/debugBoolean.js +225 -0
  231. package/src/tests/partFiles/badBoolean.json +957 -0
  232. package/src/tests/partFiles/extrudeTest.json +88 -0
  233. package/src/tests/partFiles/filletFail.json +58 -0
  234. package/src/tests/partFiles/import_TEst.part.part.json +646 -0
  235. package/src/tests/partFiles/sheetMetalHem.BREP.json +734 -0
  236. package/src/tests/test_boolean_subtract.js +27 -0
  237. package/src/tests/test_chamfer.js +17 -0
  238. package/src/tests/test_extrudeFace.js +24 -0
  239. package/src/tests/test_fillet.js +17 -0
  240. package/src/tests/test_fillet_nonClosed.js +45 -0
  241. package/src/tests/test_filletsMoreDifficult.js +46 -0
  242. package/src/tests/test_history_features_basic.js +149 -0
  243. package/src/tests/test_hole.js +282 -0
  244. package/src/tests/test_mirror.js +16 -0
  245. package/src/tests/test_offsetShellGrouping.js +85 -0
  246. package/src/tests/test_plane.js +4 -0
  247. package/src/tests/test_primitiveCone.js +11 -0
  248. package/src/tests/test_primitiveCube.js +7 -0
  249. package/src/tests/test_primitiveCylinder.js +8 -0
  250. package/src/tests/test_primitivePyramid.js +9 -0
  251. package/src/tests/test_primitiveSphere.js +17 -0
  252. package/src/tests/test_primitiveTorus.js +21 -0
  253. package/src/tests/test_pushFace.js +126 -0
  254. package/src/tests/test_sheetMetalContourFlange.js +125 -0
  255. package/src/tests/test_sheetMetal_features.js +80 -0
  256. package/src/tests/test_sketch_openLoop.js +45 -0
  257. package/src/tests/test_solidMetrics.js +58 -0
  258. package/src/tests/test_stlLoader.js +1889 -0
  259. package/src/tests/test_sweepFace.js +55 -0
  260. package/src/tests/test_tube.js +45 -0
  261. package/src/tests/test_tube_closedLoop.js +67 -0
  262. package/src/tests/tests.js +493 -0
  263. package/src/tools/assemblyConstraintDialogCapturePage.js +56 -0
  264. package/src/tools/dialogCapturePageFactory.js +227 -0
  265. package/src/tools/featureDialogCapturePage.js +47 -0
  266. package/src/tools/pmiAnnotationDialogCapturePage.js +60 -0
  267. package/src/utils/axisHelpers.js +99 -0
  268. package/src/utils/deepClone.js +69 -0
  269. package/src/utils/geometryTolerance.js +37 -0
  270. package/src/utils/normalizeTypeString.js +8 -0
  271. package/src/utils/xformMath.js +51 -0
@@ -0,0 +1,198 @@
1
+ import JSZip from 'jszip';
2
+ import { localStorage as LS } from '../idbStorage.js';
3
+
4
+ export const MODEL_STORAGE_PREFIX = '__BREP_MODEL__:';
5
+
6
+ function safeParse(json) {
7
+ try {
8
+ return JSON.parse(json);
9
+ } catch {
10
+ return null;
11
+ }
12
+ }
13
+
14
+ function decodeModelKey(key) {
15
+ try {
16
+ return decodeURIComponent(key.slice(MODEL_STORAGE_PREFIX.length));
17
+ } catch {
18
+ return key.slice(MODEL_STORAGE_PREFIX.length);
19
+ }
20
+ }
21
+
22
+ export function listComponentRecords() {
23
+ const items = [];
24
+ try {
25
+ for (let i = 0; i < LS.length; i++) {
26
+ const key = LS.key(i);
27
+ if (!key || !key.startsWith(MODEL_STORAGE_PREFIX)) continue;
28
+ const raw = LS.getItem(key);
29
+ if (!raw) continue;
30
+ const parsed = safeParse(raw);
31
+ if (!parsed || (!parsed.data3mf && !parsed.data)) continue;
32
+ const name = decodeModelKey(key);
33
+ items.push({
34
+ name,
35
+ savedAt: parsed.savedAt || null,
36
+ has3mf: typeof parsed.data3mf === 'string' && parsed.data3mf.length > 0,
37
+ record: parsed,
38
+ });
39
+ }
40
+ } catch {
41
+ // ignore storage issues
42
+ }
43
+
44
+ items.sort((a, b) => {
45
+ const aTime = a.savedAt ? Date.parse(a.savedAt) : 0;
46
+ const bTime = b.savedAt ? Date.parse(b.savedAt) : 0;
47
+ return bTime - aTime;
48
+ });
49
+
50
+ return items;
51
+ }
52
+
53
+ export function getComponentRecord(name) {
54
+ if (!name) return null;
55
+ const key = MODEL_STORAGE_PREFIX + encodeURIComponent(String(name));
56
+ try {
57
+ const raw = LS.getItem(key);
58
+ if (!raw) return null;
59
+ const parsed = safeParse(raw);
60
+ if (!parsed) return null;
61
+ return {
62
+ name,
63
+ savedAt: parsed.savedAt || null,
64
+ data3mf: typeof parsed.data3mf === 'string' ? parsed.data3mf : null,
65
+ data: parsed.data || null,
66
+ thumbnail: typeof parsed.thumbnail === 'string' ? parsed.thumbnail : null,
67
+ };
68
+ } catch {
69
+ return null;
70
+ }
71
+ }
72
+
73
+ export function base64ToUint8Array(b64) {
74
+ if (typeof b64 !== 'string' || b64.length === 0) return new Uint8Array();
75
+ let payload = b64;
76
+ if (payload.startsWith('data:') && payload.includes(';base64,')) {
77
+ payload = payload.split(';base64,')[1] || '';
78
+ }
79
+ try {
80
+ const binary = atob(payload);
81
+ const out = new Uint8Array(binary.length);
82
+ for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
83
+ return out;
84
+ } catch {
85
+ return new Uint8Array();
86
+ }
87
+ }
88
+
89
+ export function uint8ArrayToBase64(uint8) {
90
+ if (!(uint8 instanceof Uint8Array) || uint8.length === 0) return '';
91
+ const chunk = 0x8000;
92
+ let binary = '';
93
+ for (let i = 0; i < uint8.length; i += chunk) {
94
+ const sub = uint8.subarray(i, i + chunk);
95
+ binary += String.fromCharCode.apply(null, sub);
96
+ }
97
+ return btoa(binary);
98
+ }
99
+
100
+ export function setComponentRecord(name, dataObj) {
101
+ if (!name) return;
102
+ const key = MODEL_STORAGE_PREFIX + encodeURIComponent(String(name));
103
+ try {
104
+ LS.setItem(key, JSON.stringify(dataObj || {}));
105
+ } catch {}
106
+ }
107
+
108
+ export function removeComponentRecord(name) {
109
+ if (!name) return;
110
+ const key = MODEL_STORAGE_PREFIX + encodeURIComponent(String(name));
111
+ try {
112
+ LS.removeItem(key);
113
+ } catch {}
114
+ }
115
+
116
+ export async function extractThumbnailFrom3MFBase64(b64) {
117
+ try {
118
+ if (!b64) return null;
119
+ let payload = b64;
120
+ if (payload.startsWith('data:') && payload.includes(';base64,')) {
121
+ payload = payload.split(';base64,')[1] || '';
122
+ }
123
+ const bytes = base64ToUint8Array(payload);
124
+ const zip = await JSZip.loadAsync(bytes.buffer);
125
+ const files = {};
126
+ Object.keys(zip.files || {}).forEach((p) => { files[p.toLowerCase()] = p; });
127
+
128
+ const readThumb = async (lfPath) => {
129
+ const real = files[lfPath];
130
+ if (!real) return null;
131
+ const mime = lfPath.endsWith('.png') ? 'image/png' : (lfPath.match(/\.(jpe?g)$/) ? 'image/jpeg' : 'application/octet-stream');
132
+ const imgU8 = await zip.file(real).async('uint8array');
133
+ return `data:${mime};base64,${uint8ArrayToBase64(imgU8)}`;
134
+ };
135
+
136
+ const relsRoot = files['_rels/.rels'];
137
+ if (relsRoot) {
138
+ try {
139
+ const relsXml = await zip.file(relsRoot).async('string');
140
+ const relRe = /<Relationship\s+[^>]*Type="[^"]*metadata\/thumbnail[^"]*"[^>]*>/ig;
141
+ const tgtRe = /Target="([^"]+)"/i;
142
+ let match;
143
+ while ((match = relRe.exec(relsXml))) {
144
+ const tag = match[0];
145
+ const tm = tgtRe.exec(tag);
146
+ if (tm && tm[1]) {
147
+ let target = tm[1];
148
+ if (target.startsWith('/')) target = target.replace(/^\/+/, '');
149
+ else target = target.replace(/^\/+/, '');
150
+ const lf = target.toLowerCase();
151
+ const thumb = await readThumb(lf);
152
+ if (thumb) return thumb;
153
+ }
154
+ }
155
+ } catch { /* ignore */ }
156
+ }
157
+
158
+ const relsModel = files['3d/_rels/3dmodel.model.rels'];
159
+ if (relsModel) {
160
+ try {
161
+ const relsXml = await zip.file(relsModel).async('string');
162
+ const relRe = /<Relationship\s+[^>]*Type="[^"]*metadata\/thumbnail[^"]*"[^>]*>/ig;
163
+ const tgtRe = /Target="([^"]+)"/i;
164
+ let match;
165
+ while ((match = relRe.exec(relsXml))) {
166
+ const tag = match[0];
167
+ const tm = tgtRe.exec(tag);
168
+ if (tm && tm[1]) {
169
+ let target = tm[1];
170
+ if (target.startsWith('/')) target = target.replace(/^\/+/, '');
171
+ else {
172
+ target = '3D/' + target;
173
+ target = target.replace(/(^|\/)\.{2}\/(?!\.{2}|$)/g, '/');
174
+ target = target.replace(/^\/+/, '');
175
+ }
176
+ const lf = target.toLowerCase();
177
+ const thumb = await readThumb(lf);
178
+ if (thumb) return thumb;
179
+ }
180
+ }
181
+ } catch { /* ignore */ }
182
+ }
183
+
184
+ let thumbPath = Object.keys(files).find((k) => k.startsWith('metadata/') && (k.endsWith('.png') || k.endsWith('.jpg') || k.endsWith('.jpeg')));
185
+ if (!thumbPath) {
186
+ thumbPath = Object.keys(files).find((k) => k.startsWith('thumbnails/') && (k.endsWith('.png') || k.endsWith('.jpg') || k.endsWith('.jpeg')));
187
+ }
188
+ if (thumbPath) {
189
+ const real = files[thumbPath];
190
+ const mime = thumbPath.endsWith('.png') ? 'image/png' : 'image/jpeg';
191
+ const imgU8 = await zip.file(real).async('uint8array');
192
+ return `data:${mime};base64,${uint8ArrayToBase64(imgU8)}`;
193
+ }
194
+ return null;
195
+ } catch {
196
+ return null;
197
+ }
198
+ }
@@ -0,0 +1,189 @@
1
+ // ES6, zero-dependency, drop-in console interceptor.
2
+ // Creates a capturing proxy for the global `console` on instantiation,
3
+ // forwards everything to the original console, and lets you read/clear logs.
4
+ //
5
+ // Usage:
6
+ // import ConsoleCapture from './ConsoleCapture.js'
7
+ // const cap = new ConsoleCapture({ captureStack: false });
8
+ // console.log('hello'); // still prints
9
+ // cap.getLogs(); // -> [{ level:'log', args:['hello'], ... }]
10
+ // cap.clearLogs();
11
+ // cap.pause(); cap.resume(); // toggle capture
12
+ // cap.restore(); // put the original console back
13
+
14
+ export class ConsoleCapture {
15
+ constructor(options = {}) {
16
+ this.options = {
17
+ captureStack: Boolean(options.captureStack),
18
+ withTimestamp: options.withTimestamp !== false, // default true
19
+ levels: options.levels || null, // e.g., ['log','warn','error']
20
+ maxEntries: Number.isFinite(options.maxEntries) ? options.maxEntries : Infinity,
21
+ };
22
+
23
+ this._orig = (typeof window !== 'undefined' ? window.console : console) || {};
24
+ this._installed = false;
25
+ this._capturing = true;
26
+ this._logs = [];
27
+ this._nextId = 1;
28
+
29
+ this._proxy = this._buildProxy();
30
+ this.install(); // start intercepting upon creation
31
+ }
32
+
33
+ // ---------------- Public API ----------------
34
+
35
+ install() {
36
+ if (this._installed) return;
37
+ const target = typeof window !== 'undefined' ? window : globalThis;
38
+ this._prevConsole = target.console;
39
+ target.console = this._proxy;
40
+ this._installed = true;
41
+ }
42
+
43
+ restore() {
44
+ if (!this._installed) return;
45
+ const target = typeof window !== 'undefined' ? window : globalThis;
46
+ target.console = this._prevConsole || this._orig;
47
+ this._installed = false;
48
+ }
49
+
50
+ pause() { this._capturing = false; }
51
+ resume() { this._capturing = true; }
52
+
53
+ getLogs(filter = {}) {
54
+ const { level, since, until } = filter;
55
+ return this._logs.filter(entry => {
56
+ if (level && entry.level !== level) return false;
57
+ if (since && entry.time && entry.time < since) return false;
58
+ if (until && entry.time && entry.time > until) return false;
59
+ return true;
60
+ }).slice(); // shallow copy
61
+ }
62
+
63
+ clearLogs() {
64
+ this._logs.length = 0;
65
+ }
66
+
67
+ // For symmetry with your example; same names, same behavior.
68
+ get logs() { return this.getLogs(); }
69
+ getLogsAll() { return this.getLogs(); }
70
+
71
+ // ---------------- Internal ----------------
72
+
73
+ _buildProxy() {
74
+ const orig = this._orig;
75
+ const proxy = {};
76
+
77
+ // Collect all property names (functions + others) from the original console
78
+ const names = new Set([
79
+ ...Object.getOwnPropertyNames(orig),
80
+ ...Object.keys(orig)
81
+ ]);
82
+
83
+ // Common console methods across browsers/environments
84
+ const knownMethods = [
85
+ 'log','info','warn','error','debug','trace',
86
+ 'group','groupCollapsed','groupEnd',
87
+ 'table','time','timeEnd','timeLog',
88
+ 'count','countReset','assert','clear','dir','dirxml'
89
+ ];
90
+ knownMethods.forEach(n => names.add(n));
91
+
92
+ // Bind/wrap every function; copy over non-functions.
93
+ for (const name of names) {
94
+ const desc = this._safeGetDescriptor(orig, name);
95
+ if (!desc) continue;
96
+
97
+ if (typeof desc.value === 'function') {
98
+ proxy[name] = this._wrapMethod(name, orig[name]);
99
+ } else if (desc.get || desc.set) {
100
+ // Recreate getters/setters to retain behavior
101
+ Object.defineProperty(proxy, name, {
102
+ configurable: true,
103
+ enumerable: desc.enumerable,
104
+ get: desc.get ? desc.get.bind(orig) : undefined,
105
+ set: desc.set ? desc.set.bind(orig) : undefined
106
+ });
107
+ } else {
108
+ // Copy primitives/objects as-is
109
+ try {
110
+ proxy[name] = orig[name];
111
+ } catch {
112
+ // Some environments may throw on access; ignore
113
+ }
114
+ }
115
+ }
116
+
117
+ // Make it obvious (optional)
118
+ Object.defineProperty(proxy, '__capturing__', {
119
+ value: true, enumerable: false
120
+ });
121
+
122
+ return proxy;
123
+ }
124
+
125
+ _safeGetDescriptor(obj, prop) {
126
+ try {
127
+ return Object.getOwnPropertyDescriptor(obj, prop);
128
+ } catch {
129
+ return null;
130
+ }
131
+ }
132
+
133
+ _wrapMethod(level, fn) {
134
+ const self = this;
135
+
136
+ // Respect optional level filtering
137
+ const levelAllowed =
138
+ !self.options.levels || self.options.levels.includes(level);
139
+
140
+ function wrapped(...args) {
141
+ // Special-case assert: only logs if first arg is falsy
142
+ const isAssert = level === 'assert';
143
+ const shouldCaptureAssert = isAssert ? !args[0] : true;
144
+
145
+ if (self._capturing && levelAllowed && shouldCaptureAssert) {
146
+ const entry = {
147
+ id: self._nextId++,
148
+ level,
149
+ args, // keep original values (objects by reference)
150
+ };
151
+ if (self.options.withTimestamp) {
152
+ entry.time = new Date();
153
+ }
154
+ if (self.options.captureStack) {
155
+ // Discard the first two lines (Error + this wrapper)
156
+ const stack = new Error().stack || '';
157
+ entry.stack = stack.split('\n').slice(2).join('\n');
158
+ }
159
+
160
+ // Enforce maxEntries as a ring buffer if set
161
+ if (self.options.maxEntries !== Infinity && self._logs.length >= self.options.maxEntries) {
162
+ self._logs.shift();
163
+ }
164
+ self._logs.push(entry);
165
+ }
166
+
167
+ // Forward to the original function (if it exists), preserving the original `this`
168
+ try {
169
+ if (typeof fn === 'function') {
170
+ return fn.apply(self._orig, args);
171
+ }
172
+ } catch (err) {
173
+ // If the original console throws, avoid breaking the app
174
+ try {
175
+ // Last-resort fallback to native console if available
176
+ return self._orig && typeof self._orig.log === 'function'
177
+ ? self._orig.log('ConsoleCapture forwarding error:', err)
178
+ : undefined;
179
+ } catch { /* ignore */ }
180
+ }
181
+ return undefined;
182
+ }
183
+
184
+ // Keep function name for nicer stacks (non-critical)
185
+ try { Object.defineProperty(wrapped, 'name', { value: `capture_${level}` }); } catch {}
186
+
187
+ return wrapped;
188
+ }
189
+ }