@bldrs-ai/conway 1.389.1221 → 1.394.1504

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 (382) hide show
  1. package/README.md +36 -22
  2. package/compiled/Dist/ConwayGeomWasmNode.js +0 -0
  3. package/compiled/Dist/ConwayGeomWasmNodeMT.js +0 -0
  4. package/compiled/Dist/ConwayGeomWasmWeb.js +0 -0
  5. package/compiled/Dist/ConwayGeomWasmWebMT.js +1 -1
  6. package/compiled/Dist/ConwayGeomWasmWebMT.wasm +0 -0
  7. package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmNode.js +0 -0
  8. package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmNodeMT.js +0 -0
  9. package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWeb.js +0 -0
  10. package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWebMT.js +1 -1
  11. package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWebMT.wasm +0 -0
  12. package/compiled/dependencies/conway-geom/interface/conway_geometry.d.ts +19 -0
  13. package/compiled/dependencies/conway-geom/interface/conway_geometry.d.ts.map +1 -1
  14. package/compiled/dependencies/conway-geom/interface/conway_geometry.js +17 -0
  15. package/compiled/dependencies/conway-geom/interface/parameters/surface_object.d.ts +6 -0
  16. package/compiled/dependencies/conway-geom/interface/parameters/surface_object.d.ts.map +1 -1
  17. package/compiled/examples/browser-bundled.cjs +1569 -51
  18. package/compiled/examples/cli-bundled.cjs +2790 -436
  19. package/compiled/examples/cli-step-bundled.cjs +1904 -229
  20. package/compiled/examples/validator-bundled.cjs +1569 -51
  21. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.d.ts +2 -2
  22. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.d.ts.map +1 -1
  23. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_curve.gen.js +2 -2
  24. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.d.ts +3 -3
  25. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.d.ts.map +1 -1
  26. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/b_spline_surface.gen.js +3 -3
  27. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.d.ts +1 -1
  28. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.d.ts.map +1 -1
  29. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/composite_curve.gen.js +1 -1
  30. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.d.ts +1 -1
  31. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.d.ts.map +1 -1
  32. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_2d.gen.js +1 -1
  33. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.d.ts +1 -1
  34. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.d.ts.map +1 -1
  35. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_curve_3d.gen.js +1 -1
  36. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.d.ts +1 -1
  37. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.d.ts.map +1 -1
  38. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/offset_surface.gen.js +1 -1
  39. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/presentation_style_assignment.gen.d.ts.map +1 -1
  40. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/presentation_style_assignment.gen.js +2 -2
  41. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/schema_ap214.gen.js +11 -11
  42. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.d.ts +1 -1
  43. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.d.ts.map +1 -1
  44. package/compiled/src/AP214E3_2010/AP214E3_2010_gen/shape_aspect.gen.js +1 -1
  45. package/compiled/src/AP214E3_2010/ap214_command_line_main.js +7 -3
  46. package/compiled/src/AP214E3_2010/ap214_geometry_extraction.d.ts +181 -7
  47. package/compiled/src/AP214E3_2010/ap214_geometry_extraction.d.ts.map +1 -1
  48. package/compiled/src/AP214E3_2010/ap214_geometry_extraction.js +906 -137
  49. package/compiled/src/AP214E3_2010/ap214_geometry_extraction.test.js +10 -2
  50. package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.d.ts +2 -0
  51. package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.d.ts.map +1 -0
  52. package/compiled/src/AP214E3_2010/ap214_logical_attribute.test.js +114 -0
  53. package/compiled/src/AP214E3_2010/ap214_model_geometry.d.ts +6 -0
  54. package/compiled/src/AP214E3_2010/ap214_model_geometry.d.ts.map +1 -1
  55. package/compiled/src/AP214E3_2010/ap214_model_geometry.js +9 -0
  56. package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.d.ts +2 -0
  57. package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.d.ts.map +1 -0
  58. package/compiled/src/AP214E3_2010/ap214_pcurve_basis_surfaces.test.js +233 -0
  59. package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.d.ts +2 -0
  60. package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.d.ts.map +1 -0
  61. package/compiled/src/AP214E3_2010/ap214_sphere_vertex_loop.test.js +147 -0
  62. package/compiled/src/AP214E3_2010/ap214_step_model.d.ts +2 -1
  63. package/compiled/src/AP214E3_2010/ap214_step_model.d.ts.map +1 -1
  64. package/compiled/src/AP214E3_2010/ap214_step_model.js +1 -1
  65. package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.d.ts +2 -0
  66. package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.d.ts.map +1 -0
  67. package/compiled/src/AP214E3_2010/ap214_typed_select_enum.test.js +65 -0
  68. package/compiled/src/AP214E3_2010/ap214_unit_scale.test.d.ts +2 -0
  69. package/compiled/src/AP214E3_2010/ap214_unit_scale.test.d.ts.map +1 -0
  70. package/compiled/src/AP214E3_2010/ap214_unit_scale.test.js +111 -0
  71. package/compiled/src/compat/web-ifc/ap214_streamed_open.test.d.ts +2 -0
  72. package/compiled/src/compat/web-ifc/ap214_streamed_open.test.d.ts.map +1 -0
  73. package/compiled/src/compat/web-ifc/ap214_streamed_open.test.js +190 -0
  74. package/compiled/src/compat/web-ifc/coordination_export_order.test.d.ts +2 -0
  75. package/compiled/src/compat/web-ifc/coordination_export_order.test.d.ts.map +1 -0
  76. package/compiled/src/compat/web-ifc/coordination_export_order.test.js +110 -0
  77. package/compiled/src/compat/web-ifc/coordination_f64.d.ts +165 -0
  78. package/compiled/src/compat/web-ifc/coordination_f64.d.ts.map +1 -0
  79. package/compiled/src/compat/web-ifc/coordination_f64.js +286 -0
  80. package/compiled/src/compat/web-ifc/coordination_f64.test.d.ts +2 -0
  81. package/compiled/src/compat/web-ifc/coordination_f64.test.d.ts.map +1 -0
  82. package/compiled/src/compat/web-ifc/coordination_f64.test.js +225 -0
  83. package/compiled/src/compat/web-ifc/ifc_api.d.ts +154 -0
  84. package/compiled/src/compat/web-ifc/ifc_api.d.ts.map +1 -1
  85. package/compiled/src/compat/web-ifc/ifc_api.js +211 -3
  86. package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.d.ts +2 -0
  87. package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.d.ts.map +1 -0
  88. package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.js +288 -0
  89. package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts +39 -0
  90. package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts.map +1 -1
  91. package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.d.ts +30 -0
  92. package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.d.ts.map +1 -1
  93. package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.js +83 -0
  94. package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.d.ts +2 -0
  95. package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.d.ts.map +1 -0
  96. package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.js +383 -0
  97. package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.d.ts +2 -0
  98. package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.d.ts.map +1 -0
  99. package/compiled/src/compat/web-ifc/ifc_api_preview_coordination.test.js +124 -0
  100. package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts +132 -0
  101. package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts.map +1 -1
  102. package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.js +488 -92
  103. package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts +268 -0
  104. package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts.map +1 -1
  105. package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.js +996 -149
  106. package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.d.ts +2 -0
  107. package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.d.ts.map +1 -0
  108. package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.js +129 -0
  109. package/compiled/src/compat/web-ifc/spatial_imposter.d.ts +134 -0
  110. package/compiled/src/compat/web-ifc/spatial_imposter.d.ts.map +1 -0
  111. package/compiled/src/compat/web-ifc/spatial_imposter.js +933 -0
  112. package/compiled/src/compat/web-ifc/spatial_imposter.test.d.ts +2 -0
  113. package/compiled/src/compat/web-ifc/spatial_imposter.test.d.ts.map +1 -0
  114. package/compiled/src/compat/web-ifc/spatial_imposter.test.js +467 -0
  115. package/compiled/src/compat/web-ifc/store_preview_channel.d.ts +187 -0
  116. package/compiled/src/compat/web-ifc/store_preview_channel.d.ts.map +1 -0
  117. package/compiled/src/compat/web-ifc/store_preview_channel.js +524 -0
  118. package/compiled/src/compat/web-ifc/store_preview_channel.test.d.ts +2 -0
  119. package/compiled/src/compat/web-ifc/store_preview_channel.test.d.ts.map +1 -0
  120. package/compiled/src/compat/web-ifc/store_preview_channel.test.js +234 -0
  121. package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts +306 -0
  122. package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts.map +1 -0
  123. package/compiled/src/compat/web-ifc/streamed_preview_channel.js +580 -0
  124. package/compiled/src/compat/web-ifc/web_wasm_directory.test.d.ts +2 -0
  125. package/compiled/src/compat/web-ifc/web_wasm_directory.test.d.ts.map +1 -0
  126. package/compiled/src/compat/web-ifc/web_wasm_directory.test.js +22 -0
  127. package/compiled/src/core/composed_model_skeleton.d.ts +63 -0
  128. package/compiled/src/core/composed_model_skeleton.d.ts.map +1 -0
  129. package/compiled/src/core/composed_model_skeleton.js +66 -0
  130. package/compiled/src/core/composed_model_skeleton.test.d.ts +2 -0
  131. package/compiled/src/core/composed_model_skeleton.test.d.ts.map +1 -0
  132. package/compiled/src/core/composed_model_skeleton.test.js +69 -0
  133. package/compiled/src/core/demand_geometry_queue.d.ts +147 -0
  134. package/compiled/src/core/demand_geometry_queue.d.ts.map +1 -0
  135. package/compiled/src/core/demand_geometry_queue.js +223 -0
  136. package/compiled/src/core/demand_geometry_queue.test.d.ts +2 -0
  137. package/compiled/src/core/demand_geometry_queue.test.d.ts.map +1 -0
  138. package/compiled/src/core/demand_geometry_queue.test.js +133 -0
  139. package/compiled/src/core/demand_residency_pump.d.ts +93 -0
  140. package/compiled/src/core/demand_residency_pump.d.ts.map +1 -0
  141. package/compiled/src/core/demand_residency_pump.js +120 -0
  142. package/compiled/src/core/demand_residency_pump.test.d.ts +2 -0
  143. package/compiled/src/core/demand_residency_pump.test.d.ts.map +1 -0
  144. package/compiled/src/core/demand_residency_pump.test.js +148 -0
  145. package/compiled/src/core/geometry_tile_bindings.d.ts +110 -0
  146. package/compiled/src/core/geometry_tile_bindings.d.ts.map +1 -0
  147. package/compiled/src/core/geometry_tile_bindings.js +76 -0
  148. package/compiled/src/core/geometry_tile_bindings.test.d.ts +2 -0
  149. package/compiled/src/core/geometry_tile_bindings.test.d.ts.map +1 -0
  150. package/compiled/src/core/geometry_tile_bindings.test.js +211 -0
  151. package/compiled/src/core/geometry_tile_pool.d.ts +99 -0
  152. package/compiled/src/core/geometry_tile_pool.d.ts.map +1 -0
  153. package/compiled/src/core/geometry_tile_pool.js +104 -0
  154. package/compiled/src/core/geometry_tile_pool.test.d.ts +2 -0
  155. package/compiled/src/core/geometry_tile_pool.test.d.ts.map +1 -0
  156. package/compiled/src/core/geometry_tile_pool.test.js +180 -0
  157. package/compiled/src/core/mem/chunked_pool.d.ts +116 -0
  158. package/compiled/src/core/mem/chunked_pool.d.ts.map +1 -0
  159. package/compiled/src/core/mem/chunked_pool.js +149 -0
  160. package/compiled/src/core/mem/chunked_pool.test.d.ts +2 -0
  161. package/compiled/src/core/mem/chunked_pool.test.d.ts.map +1 -0
  162. package/compiled/src/core/mem/chunked_pool.test.js +63 -0
  163. package/compiled/src/core/mem/shared_asset_pool.d.ts +82 -0
  164. package/compiled/src/core/mem/shared_asset_pool.d.ts.map +1 -0
  165. package/compiled/src/core/mem/shared_asset_pool.js +113 -0
  166. package/compiled/src/core/mem/shared_asset_pool.test.d.ts +2 -0
  167. package/compiled/src/core/mem/shared_asset_pool.test.d.ts.map +1 -0
  168. package/compiled/src/core/mem/shared_asset_pool.test.js +49 -0
  169. package/compiled/src/core/model_registry.d.ts +87 -0
  170. package/compiled/src/core/model_registry.d.ts.map +1 -0
  171. package/compiled/src/core/model_registry.js +101 -0
  172. package/compiled/src/core/model_registry.test.d.ts +2 -0
  173. package/compiled/src/core/model_registry.test.d.ts.map +1 -0
  174. package/compiled/src/core/model_registry.test.js +60 -0
  175. package/compiled/src/core/model_uri.d.ts +57 -0
  176. package/compiled/src/core/model_uri.d.ts.map +1 -0
  177. package/compiled/src/core/model_uri.js +101 -0
  178. package/compiled/src/core/model_uri.test.d.ts +2 -0
  179. package/compiled/src/core/model_uri.test.d.ts.map +1 -0
  180. package/compiled/src/core/model_uri.test.js +49 -0
  181. package/compiled/src/core/progress.d.ts +16 -2
  182. package/compiled/src/core/progress.d.ts.map +1 -1
  183. package/compiled/src/core/progress.js +31 -5
  184. package/compiled/src/core/progress.test.js +11 -2
  185. package/compiled/src/core/progress_log.d.ts +1 -0
  186. package/compiled/src/core/progress_log.d.ts.map +1 -1
  187. package/compiled/src/core/progress_log.js +7 -2
  188. package/compiled/src/core/progress_log.test.js +21 -0
  189. package/compiled/src/core/shared_byte_budget.d.ts +60 -0
  190. package/compiled/src/core/shared_byte_budget.d.ts.map +1 -0
  191. package/compiled/src/core/shared_byte_budget.js +85 -0
  192. package/compiled/src/core/shared_byte_budget.test.d.ts +2 -0
  193. package/compiled/src/core/shared_byte_budget.test.d.ts.map +1 -0
  194. package/compiled/src/core/shared_byte_budget.test.js +55 -0
  195. package/compiled/src/core/wasm_heap.d.ts +208 -0
  196. package/compiled/src/core/wasm_heap.d.ts.map +1 -0
  197. package/compiled/src/core/wasm_heap.js +417 -0
  198. package/compiled/src/core/wasm_heap.test.d.ts +2 -0
  199. package/compiled/src/core/wasm_heap.test.d.ts.map +1 -0
  200. package/compiled/src/core/wasm_heap.test.js +546 -0
  201. package/compiled/src/demand/index.d.ts +23 -0
  202. package/compiled/src/demand/index.d.ts.map +1 -0
  203. package/compiled/src/demand/index.js +22 -0
  204. package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.d.ts +1 -1
  205. package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.d.ts.map +1 -1
  206. package/compiled/src/ifc/ifc4_gen/IfcLogical.gen.js +1 -1
  207. package/compiled/src/ifc/ifc4_gen/IfcPresentationStyleAssignment.gen.d.ts.map +1 -1
  208. package/compiled/src/ifc/ifc4_gen/IfcPresentationStyleAssignment.gen.js +2 -2
  209. package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.d.ts +1 -1
  210. package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.d.ts.map +1 -1
  211. package/compiled/src/ifc/ifc4_gen/IfcRelInterferesElements.gen.js +1 -1
  212. package/compiled/src/ifc/ifc4_gen/schema_ifc.gen.js +2 -2
  213. package/compiled/src/ifc/ifc_demand_extraction.test.d.ts +2 -0
  214. package/compiled/src/ifc/ifc_demand_extraction.test.d.ts.map +1 -0
  215. package/compiled/src/ifc/ifc_demand_extraction.test.js +251 -0
  216. package/compiled/src/ifc/ifc_geometry_extraction.d.ts +367 -6
  217. package/compiled/src/ifc/ifc_geometry_extraction.d.ts.map +1 -1
  218. package/compiled/src/ifc/ifc_geometry_extraction.js +1322 -389
  219. package/compiled/src/ifc/ifc_grid_placement.test.d.ts +2 -0
  220. package/compiled/src/ifc/ifc_grid_placement.test.d.ts.map +1 -0
  221. package/compiled/src/ifc/ifc_grid_placement.test.js +261 -0
  222. package/compiled/src/ifc/ifc_model_geometry.d.ts +12 -0
  223. package/compiled/src/ifc/ifc_model_geometry.d.ts.map +1 -1
  224. package/compiled/src/ifc/ifc_model_geometry.js +15 -0
  225. package/compiled/src/ifc/ifc_regression_batch_main.js +210 -12
  226. package/compiled/src/ifc/ifc_spatial_skeleton.d.ts +145 -0
  227. package/compiled/src/ifc/ifc_spatial_skeleton.d.ts.map +1 -0
  228. package/compiled/src/ifc/ifc_spatial_skeleton.js +266 -0
  229. package/compiled/src/ifc/ifc_spatial_skeleton.test.d.ts +2 -0
  230. package/compiled/src/ifc/ifc_spatial_skeleton.test.d.ts.map +1 -0
  231. package/compiled/src/ifc/ifc_spatial_skeleton.test.js +199 -0
  232. package/compiled/src/ifc/ifc_step_model.d.ts +6 -2
  233. package/compiled/src/ifc/ifc_step_model.d.ts.map +1 -1
  234. package/compiled/src/ifc/ifc_step_model.js +6 -4
  235. package/compiled/src/ifc/ifc_step_parser.d.ts +58 -0
  236. package/compiled/src/ifc/ifc_step_parser.d.ts.map +1 -1
  237. package/compiled/src/ifc/ifc_step_parser.js +64 -0
  238. package/compiled/src/ifc/ifc_stream_model.test.d.ts +2 -0
  239. package/compiled/src/ifc/ifc_stream_model.test.d.ts.map +1 -0
  240. package/compiled/src/ifc/ifc_stream_model.test.js +70 -0
  241. package/compiled/src/ifc/ifc_stream_open.d.ts +131 -0
  242. package/compiled/src/ifc/ifc_stream_open.d.ts.map +1 -0
  243. package/compiled/src/ifc/ifc_stream_open.js +116 -0
  244. package/compiled/src/ifc/ifc_stream_open.test.d.ts +2 -0
  245. package/compiled/src/ifc/ifc_stream_open.test.d.ts.map +1 -0
  246. package/compiled/src/ifc/ifc_stream_open.test.js +230 -0
  247. package/compiled/src/ifc/ifc_tile_extractor.d.ts +84 -0
  248. package/compiled/src/ifc/ifc_tile_extractor.d.ts.map +1 -0
  249. package/compiled/src/ifc/ifc_tile_extractor.js +134 -0
  250. package/compiled/src/ifc/ifc_tile_extractor.test.d.ts +2 -0
  251. package/compiled/src/ifc/ifc_tile_extractor.test.d.ts.map +1 -0
  252. package/compiled/src/ifc/ifc_tile_extractor.test.js +118 -0
  253. package/compiled/src/ifc/ifc_typed_select_enum.test.d.ts +2 -0
  254. package/compiled/src/ifc/ifc_typed_select_enum.test.d.ts.map +1 -0
  255. package/compiled/src/ifc/ifc_typed_select_enum.test.js +60 -0
  256. package/compiled/src/index.d.ts +21 -1
  257. package/compiled/src/index.d.ts.map +1 -1
  258. package/compiled/src/index.js +28 -1
  259. package/compiled/src/logging/logger.d.ts +16 -2
  260. package/compiled/src/logging/logger.d.ts.map +1 -1
  261. package/compiled/src/logging/logger.js +34 -7
  262. package/compiled/src/logging/logger.test.js +30 -0
  263. package/compiled/src/mem/index.d.ts +17 -0
  264. package/compiled/src/mem/index.d.ts.map +1 -0
  265. package/compiled/src/mem/index.js +16 -0
  266. package/compiled/src/namespace_surface.test.d.ts +2 -0
  267. package/compiled/src/namespace_surface.test.d.ts.map +1 -0
  268. package/compiled/src/namespace_surface.test.js +43 -0
  269. package/compiled/src/parsing/parsing_buffer.d.ts +23 -0
  270. package/compiled/src/parsing/parsing_buffer.d.ts.map +1 -1
  271. package/compiled/src/parsing/parsing_buffer.js +31 -0
  272. package/compiled/src/scripts/model_report_displacement.test.d.ts +2 -0
  273. package/compiled/src/scripts/model_report_displacement.test.d.ts.map +1 -0
  274. package/compiled/src/scripts/model_report_displacement.test.js +104 -0
  275. package/compiled/src/scripts/render_glb_paths.test.d.ts +2 -0
  276. package/compiled/src/scripts/render_glb_paths.test.d.ts.map +1 -0
  277. package/compiled/src/scripts/render_glb_paths.test.js +115 -0
  278. package/compiled/src/step/indexing/step_type_indexer.d.ts +20 -0
  279. package/compiled/src/step/indexing/step_type_indexer.d.ts.map +1 -1
  280. package/compiled/src/step/indexing/step_type_indexer.js +67 -0
  281. package/compiled/src/step/parsing/byte_source.d.ts +153 -0
  282. package/compiled/src/step/parsing/byte_source.d.ts.map +1 -0
  283. package/compiled/src/step/parsing/byte_source.js +106 -0
  284. package/compiled/src/step/parsing/byte_source.test.d.ts +2 -0
  285. package/compiled/src/step/parsing/byte_source.test.d.ts.map +1 -0
  286. package/compiled/src/step/parsing/byte_source.test.js +47 -0
  287. package/compiled/src/step/parsing/byte_source_node.d.ts +41 -0
  288. package/compiled/src/step/parsing/byte_source_node.d.ts.map +1 -0
  289. package/compiled/src/step/parsing/byte_source_node.js +54 -0
  290. package/compiled/src/step/parsing/columnar_index.d.ts +103 -0
  291. package/compiled/src/step/parsing/columnar_index.d.ts.map +1 -0
  292. package/compiled/src/step/parsing/columnar_index.js +224 -0
  293. package/compiled/src/step/parsing/columnar_index.test.d.ts +2 -0
  294. package/compiled/src/step/parsing/columnar_index.test.d.ts.map +1 -0
  295. package/compiled/src/step/parsing/columnar_index.test.js +155 -0
  296. package/compiled/src/step/parsing/cross_reference_registry.d.ts +95 -0
  297. package/compiled/src/step/parsing/cross_reference_registry.d.ts.map +1 -0
  298. package/compiled/src/step/parsing/cross_reference_registry.js +91 -0
  299. package/compiled/src/step/parsing/cross_reference_registry.test.d.ts +2 -0
  300. package/compiled/src/step/parsing/cross_reference_registry.test.d.ts.map +1 -0
  301. package/compiled/src/step/parsing/cross_reference_registry.test.js +66 -0
  302. package/compiled/src/step/parsing/decode_utf8.d.ts +15 -0
  303. package/compiled/src/step/parsing/decode_utf8.d.ts.map +1 -1
  304. package/compiled/src/step/parsing/decode_utf8.js +28 -0
  305. package/compiled/src/step/parsing/express_ref_scan.d.ts +20 -0
  306. package/compiled/src/step/parsing/express_ref_scan.d.ts.map +1 -0
  307. package/compiled/src/step/parsing/express_ref_scan.js +91 -0
  308. package/compiled/src/step/parsing/express_ref_scan.test.d.ts +2 -0
  309. package/compiled/src/step/parsing/express_ref_scan.test.d.ts.map +1 -0
  310. package/compiled/src/step/parsing/express_ref_scan.test.js +28 -0
  311. package/compiled/src/step/parsing/index_sidecar.d.ts +81 -0
  312. package/compiled/src/step/parsing/index_sidecar.d.ts.map +1 -0
  313. package/compiled/src/step/parsing/index_sidecar.js +283 -0
  314. package/compiled/src/step/parsing/index_sidecar.test.d.ts +2 -0
  315. package/compiled/src/step/parsing/index_sidecar.test.d.ts.map +1 -0
  316. package/compiled/src/step/parsing/index_sidecar.test.js +122 -0
  317. package/compiled/src/step/parsing/inf_recovery_index.test.d.ts +2 -0
  318. package/compiled/src/step/parsing/inf_recovery_index.test.d.ts.map +1 -0
  319. package/compiled/src/step/parsing/inf_recovery_index.test.js +108 -0
  320. package/compiled/src/step/parsing/prefix_type_index.d.ts +124 -0
  321. package/compiled/src/step/parsing/prefix_type_index.d.ts.map +1 -0
  322. package/compiled/src/step/parsing/prefix_type_index.js +207 -0
  323. package/compiled/src/step/parsing/prefix_type_index.test.d.ts +2 -0
  324. package/compiled/src/step/parsing/prefix_type_index.test.d.ts.map +1 -0
  325. package/compiled/src/step/parsing/prefix_type_index.test.js +298 -0
  326. package/compiled/src/step/parsing/range_byte_source.d.ts +69 -0
  327. package/compiled/src/step/parsing/range_byte_source.d.ts.map +1 -0
  328. package/compiled/src/step/parsing/range_byte_source.js +78 -0
  329. package/compiled/src/step/parsing/range_byte_source.test.d.ts +2 -0
  330. package/compiled/src/step/parsing/range_byte_source.test.d.ts.map +1 -0
  331. package/compiled/src/step/parsing/range_byte_source.test.js +70 -0
  332. package/compiled/src/step/parsing/record_event.d.ts +23 -0
  333. package/compiled/src/step/parsing/record_event.d.ts.map +1 -0
  334. package/compiled/src/step/parsing/record_event.js +1 -0
  335. package/compiled/src/step/parsing/record_field_cursor.d.ts +94 -0
  336. package/compiled/src/step/parsing/record_field_cursor.d.ts.map +1 -0
  337. package/compiled/src/step/parsing/record_field_cursor.js +189 -0
  338. package/compiled/src/step/parsing/step_deserialization_functions.d.ts +29 -0
  339. package/compiled/src/step/parsing/step_deserialization_functions.d.ts.map +1 -1
  340. package/compiled/src/step/parsing/step_deserialization_functions.js +45 -0
  341. package/compiled/src/step/parsing/step_deserialization_functions.test.js +59 -1
  342. package/compiled/src/step/parsing/step_parser.d.ts +66 -1
  343. package/compiled/src/step/parsing/step_parser.d.ts.map +1 -1
  344. package/compiled/src/step/parsing/step_parser.js +164 -10
  345. package/compiled/src/step/parsing/step_string_parser.js +8 -8
  346. package/compiled/src/step/parsing/streaming_index_builder.d.ts +141 -0
  347. package/compiled/src/step/parsing/streaming_index_builder.d.ts.map +1 -0
  348. package/compiled/src/step/parsing/streaming_index_builder.js +280 -0
  349. package/compiled/src/step/parsing/streaming_index_builder.test.d.ts +2 -0
  350. package/compiled/src/step/parsing/streaming_index_builder.test.d.ts.map +1 -0
  351. package/compiled/src/step/parsing/streaming_index_builder.test.js +107 -0
  352. package/compiled/src/step/parsing/streaming_index_builder_async.test.d.ts +2 -0
  353. package/compiled/src/step/parsing/streaming_index_builder_async.test.d.ts.map +1 -0
  354. package/compiled/src/step/parsing/streaming_index_builder_async.test.js +109 -0
  355. package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts +71 -0
  356. package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts.map +1 -0
  357. package/compiled/src/step/parsing/streaming_record_dispatcher.js +88 -0
  358. package/compiled/src/step/parsing/streaming_record_dispatcher.test.d.ts +2 -0
  359. package/compiled/src/step/parsing/streaming_record_dispatcher.test.d.ts.map +1 -0
  360. package/compiled/src/step/parsing/streaming_record_dispatcher.test.js +66 -0
  361. package/compiled/src/step/parsing/uint32_sink.d.ts +72 -0
  362. package/compiled/src/step/parsing/uint32_sink.d.ts.map +1 -0
  363. package/compiled/src/step/parsing/uint32_sink.js +180 -0
  364. package/compiled/src/step/parsing/uint32_sink.test.d.ts +2 -0
  365. package/compiled/src/step/parsing/uint32_sink.test.d.ts.map +1 -0
  366. package/compiled/src/step/parsing/uint32_sink.test.js +199 -0
  367. package/compiled/src/step/step_buffer_provider.d.ts +48 -3
  368. package/compiled/src/step/step_buffer_provider.d.ts.map +1 -1
  369. package/compiled/src/step/step_buffer_provider.js +60 -11
  370. package/compiled/src/step/step_buffer_provider.test.js +14 -0
  371. package/compiled/src/step/step_entity_base.d.ts +65 -3
  372. package/compiled/src/step/step_entity_base.d.ts.map +1 -1
  373. package/compiled/src/step/step_entity_base.js +135 -3
  374. package/compiled/src/step/step_model_base.d.ts +221 -8
  375. package/compiled/src/step/step_model_base.d.ts.map +1 -1
  376. package/compiled/src/step/step_model_base.js +542 -7
  377. package/compiled/src/stream/index.d.ts +34 -0
  378. package/compiled/src/stream/index.d.ts.map +1 -0
  379. package/compiled/src/stream/index.js +32 -0
  380. package/compiled/src/version/version.js +1 -1
  381. package/compiled/tsconfig.tsbuildinfo +1 -1
  382. package/package.json +16 -1
@@ -3,6 +3,9 @@ import ParsingBuffer from "../../parsing/parsing_buffer.js";
3
3
  import { IfcApiProxyAP214 } from "./ifc_api_proxy_ap214.js";
4
4
  import { IfcApiProxyIfc } from "./ifc_api_proxy_ifc.js";
5
5
  import Logger from "../../logging/logger.js";
6
+ /** Prefix used to sniff FILE_SCHEMA without paging the whole file. */
7
+ // eslint-disable-next-line no-magic-numbers
8
+ const STORE_DETECT_PREFIX_BYTES = 64 * 1024;
6
9
  /**
7
10
  * The factory to construct models.
8
11
  */
@@ -66,6 +69,86 @@ export class IfcApiModelPassthroughFactory {
66
69
  Logger.error("No type detected when constructing model");
67
70
  }
68
71
  }
72
+ /**
73
+ * Streamed-open twin of fromAsync (used by OpenModelStreamed): IFC
74
+ * models parse through the streaming columnar indexer (no per-record
75
+ * object phase — see IfcApiProxyIfc.createStreamed); everything else
76
+ * behaves like fromAsync. Non-IFC formats and any streamed-open
77
+ * failure fall back to the classic cooperative path, so this never
78
+ * does worse than fromAsync — the safety net behind embedder
79
+ * feature flags.
80
+ *
81
+ * @param modelID
82
+ * @param data
83
+ * @param wasmModule
84
+ * @param settings
85
+ * @return {Promise<IfcApiModelPassthrough | undefined>}
86
+ */
87
+ static async fromStreamed(modelID, data, wasmModule, settings) {
88
+ const modelFormat = ModelFormatDetector.detect(new ParsingBuffer(data));
89
+ if (modelFormat === ModelFormatType.IFC) {
90
+ try {
91
+ return settings?.DEFER_GEOMETRY === true ?
92
+ await IfcApiProxyIfc.createDeferred(modelID, data, wasmModule, settings) :
93
+ await IfcApiProxyIfc.createStreamed(modelID, data, wasmModule, settings);
94
+ }
95
+ catch (e) {
96
+ const message = e instanceof Error ? e.message : String(e);
97
+ Logger.warning(`Streamed open failed for model ${modelID}, ` +
98
+ `falling back to classic open: ${message}`);
99
+ }
100
+ }
101
+ // STEP demand parity: AP214 (and the AP203/AP242 fall-throughs)
102
+ // get the streamed columnar open — index columnar from birth, no
103
+ // per-record object phase — and, with DEFER_GEOMETRY, the deferred
104
+ // assembly-tree unit pump (phase 2), so STEP models stream
105
+ // progressively through ExtractGeometryBatch just like IFC.
106
+ if (modelFormat === ModelFormatType.AP214 ||
107
+ modelFormat === ModelFormatType.AP203 ||
108
+ modelFormat === ModelFormatType.AP242) {
109
+ try {
110
+ return settings?.DEFER_GEOMETRY === true ?
111
+ await IfcApiProxyAP214.createDeferred(modelID, data, wasmModule, settings) :
112
+ await IfcApiProxyAP214.createStreamed(modelID, data, wasmModule, settings);
113
+ }
114
+ catch (e) {
115
+ const message = e instanceof Error ? e.message : String(e);
116
+ Logger.warning(`Streamed STEP open failed for model ${modelID}, ` +
117
+ `falling back to classic open: ${message}`);
118
+ }
119
+ }
120
+ return IfcApiModelPassthroughFactory.fromAsync(modelID, data, wasmModule, settings);
121
+ }
122
+ /**
123
+ * Store-backed open (M1b): IFC models parse through a moving window
124
+ * over `store` and stay windowed from birth. Non-IFC formats are not
125
+ * implemented on this path — the caller should fall back to buffering
126
+ * and fromStreamed.
127
+ *
128
+ * @param modelID
129
+ * @param store External store holding the source bytes.
130
+ * @param wasmModule
131
+ * @param settings
132
+ * @return {Promise<IfcApiModelPassthrough | undefined>}
133
+ */
134
+ static async fromStore(modelID, store, wasmModule, settings) {
135
+ const prefixLen = Math.min(store.byteLength, STORE_DETECT_PREFIX_BYTES);
136
+ const prefix = await store.read(0, prefixLen);
137
+ const modelFormat = ModelFormatDetector.detect(new ParsingBuffer(prefix));
138
+ if (modelFormat === ModelFormatType.IFC) {
139
+ try {
140
+ return await IfcApiProxyIfc.createFromStore(modelID, store, wasmModule, settings);
141
+ }
142
+ catch (e) {
143
+ const message = e instanceof Error ? e.message : String(e);
144
+ Logger.warning(`Store-backed open failed for model ${modelID}: ${message}`);
145
+ }
146
+ }
147
+ else {
148
+ Logger.warning("Store-backed open is IFC-only; use OpenModelStreamed with a buffer " +
149
+ `for format ${modelFormat}`);
150
+ }
151
+ }
69
152
  /**
70
153
  * Cooperative twin of from() (used by OpenModelAsync): the data parse
71
154
  * runs with periodic event-loop yields so progress UI can repaint
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ifc_api_preview_channel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ifc_api_preview_channel.test.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/ifc_api_preview_channel.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,383 @@
1
+ /* eslint-disable no-magic-numbers */
2
+ // Parse-time preview channel (demand/tiled rendering slice A2): prefix
3
+ // snapshots of the live columnar sink must be exact prefixes of the final
4
+ // columns, and a full drain of the channel (prefix == whole file) must
5
+ // reproduce the classic StreamAllMeshes instance set — same entities,
6
+ // same geometry ids, same placed transforms — since the durable pump the
7
+ // preview hands over to is already pinned to classic parity.
8
+ import * as fs from "fs";
9
+ import { beforeAll, describe, expect, test } from "@jest/globals";
10
+ import { ConwayGeometry } from "../../../dependencies/conway-geom/index.js";
11
+ import IfcStepParser from "../../ifc/ifc_step_parser.js";
12
+ import { BufferByteSource } from "../../step/parsing/byte_source.js";
13
+ import { ColumnarIndexSink, } from "../../step/parsing/columnar_index.js";
14
+ import { ParseResult } from "../../step/parsing/step_parser.js";
15
+ import { buildIndexStreaming } from "../../step/parsing/streaming_index_builder.js";
16
+ import { IfcAPI } from "./ifc_api.js";
17
+ import { ifcPreviewAdapter, StreamedPreviewChannel, } from "./streamed_preview_channel.js";
18
+ const SETTINGS = { COORDINATE_TO_ORIGIN: true, USE_FAST_BOOLS: true };
19
+ const POOL = 1024 * 1024;
20
+ let api;
21
+ let conwayGeometry;
22
+ let data;
23
+ /**
24
+ * Parse an IFC data block into a fresh columnar sink.
25
+ *
26
+ * @param wrap Optional sink wrapper (snapshot triggers).
27
+ * @param bytes The source bytes (defaults to index.ifc).
28
+ * @return {ColumnarIndexSink} The filled sink.
29
+ */
30
+ function buildSink(wrap, bytes) {
31
+ const sink = new ColumnarIndexSink();
32
+ const { result } = buildIndexStreaming(new BufferByteSource(bytes ?? data), IfcStepParser.Instance, POOL, void 0, wrap !== void 0 ? wrap(sink) : sink);
33
+ expect(result).toBe(ParseResult.COMPLETE);
34
+ return sink;
35
+ }
36
+ /**
37
+ * Classic reference: expressID -> list of placed instances.
38
+ *
39
+ * @param modelID An open classic model.
40
+ * @return {Map} expressID -> {geometryExpressID, flatTransformation}[].
41
+ */
42
+ function classicInstances(modelID) {
43
+ const instances = new Map();
44
+ api.StreamAllMeshes(modelID, (mesh) => {
45
+ const list = instances.get(mesh.expressID) ?? [];
46
+ for (let where = 0; where < mesh.geometries.size(); ++where) {
47
+ const placed = mesh.geometries.get(where);
48
+ list.push({
49
+ geometryExpressID: placed.geometryExpressID,
50
+ flatTransformation: [...placed.flatTransformation],
51
+ });
52
+ }
53
+ instances.set(mesh.expressID, list);
54
+ });
55
+ return instances;
56
+ }
57
+ beforeAll(async () => {
58
+ api = new IfcAPI();
59
+ await api.Init();
60
+ conwayGeometry = new ConwayGeometry();
61
+ expect(await conwayGeometry.initialize()).toBe(true);
62
+ data = new Uint8Array(fs.readFileSync("data/index.ifc"));
63
+ }, 120000);
64
+ describe("ColumnarIndexSink.snapshot", () => {
65
+ test("a mid-parse snapshot is an exact prefix of the final columns", () => {
66
+ const snapshotAt = 50;
67
+ let snapshot;
68
+ const sink = buildSink((inner) => ({
69
+ pushTopLevel: (entry) => {
70
+ inner.pushTopLevel(entry);
71
+ if (inner.topLevelCount === snapshotAt) {
72
+ snapshot = inner.snapshot();
73
+ }
74
+ },
75
+ reset: () => inner.reset(),
76
+ }));
77
+ const full = sink.finalize();
78
+ expect(snapshot).toBeDefined();
79
+ expect(snapshot.firstInlineElement).toBe(snapshotAt);
80
+ expect(full.firstInlineElement).toBeGreaterThan(snapshotAt);
81
+ for (let where = 0; where < snapshotAt; ++where) {
82
+ expect(snapshot.address[where]).toBe(full.address[where]);
83
+ expect(snapshot.length[where]).toBe(full.length[where]);
84
+ expect(snapshot.typeID[where]).toBe(full.typeID[where]);
85
+ expect(snapshot.expressID[where]).toBe(full.expressID[where]);
86
+ }
87
+ });
88
+ test("snapshotting does not disturb the sink (finalize sees everything)", () => {
89
+ const undisturbed = buildSink().finalize();
90
+ const snapshotted = buildSink((inner) => ({
91
+ pushTopLevel: (entry) => {
92
+ inner.pushTopLevel(entry);
93
+ // Snapshot aggressively — every 25 records.
94
+ if (inner.topLevelCount % 25 === 0) {
95
+ inner.snapshot();
96
+ }
97
+ },
98
+ reset: () => inner.reset(),
99
+ })).finalize();
100
+ expect(snapshotted.count).toBe(undisturbed.count);
101
+ expect(snapshotted.firstInlineElement).toBe(undisturbed.firstInlineElement);
102
+ expect([...snapshotted.address]).toEqual([...undisturbed.address]);
103
+ expect([...snapshotted.expressID]).toEqual([...undisturbed.expressID]);
104
+ });
105
+ });
106
+ describe("StreamedPreviewChannel", () => {
107
+ test("a full drain reproduces the classic instance set exactly", async () => {
108
+ const classicID = api.OpenModel(data, SETTINGS);
109
+ const classic = classicInstances(classicID);
110
+ let classicTotal = 0;
111
+ for (const list of classic.values()) {
112
+ classicTotal += list.length;
113
+ }
114
+ expect(classicTotal).toBeGreaterThan(0);
115
+ // Channel over a finished sink: the "prefix" is the whole file, so a
116
+ // drain must be a complete, classic-parity extraction.
117
+ const sink = buildSink();
118
+ const payloads = [];
119
+ const channel = new StreamedPreviewChannel(data, conwayGeometry, sink, ifcPreviewAdapter(), true, (mesh) => payloads.push(mesh), void 0, void 0, 1);
120
+ channel.drainForTest();
121
+ expect(payloads.length).toBe(classicTotal);
122
+ // Every payload matches a classic instance of the same entity and
123
+ // geometry, with the same placed transform.
124
+ const unmatched = new Map();
125
+ for (const [expressID, list] of classic) {
126
+ unmatched.set(expressID, list.map((entry) => ({ ...entry })));
127
+ }
128
+ for (const payload of payloads) {
129
+ const candidates = unmatched.get(payload.expressID);
130
+ expect(candidates).toBeDefined();
131
+ const matchIndex = candidates.findIndex((candidate) => candidate.geometryExpressID === payload.geometryExpressID &&
132
+ candidate.flatTransformation.every((value, where) => Math.abs(value - payload.flatTransformation[where]) < 0.000001));
133
+ expect(matchIndex).toBeGreaterThanOrEqual(0);
134
+ candidates.splice(matchIndex, 1);
135
+ }
136
+ // Geometry payloads: exactly one carrier per distinct geometry, each
137
+ // carrying a sane interleaved buffer.
138
+ const carriers = payloads.filter((payload) => payload.vertexData !== void 0);
139
+ const distinctGeometry = new Set(payloads.map((p) => p.geometryExpressID));
140
+ expect(carriers.length).toBe(distinctGeometry.size);
141
+ for (const carrier of carriers) {
142
+ expect(carrier.vertexData.length % 6).toBe(0);
143
+ expect(carrier.vertexData.length).toBeGreaterThan(0);
144
+ expect(carrier.indexData.length % 3).toBe(0);
145
+ expect(carrier.indexData.length).toBeGreaterThan(0);
146
+ }
147
+ // The channel derived and pinned a coordination frame (proved
148
+ // equivalent to classic's by the transform parity above), and the
149
+ // deferred open must keep the classic GetCoordinationMatrix
150
+ // contract: identity, because placed transforms are premultiplied
151
+ // and consumers stamp the result onto assembled models — a
152
+ // non-identity return would coordinate twice.
153
+ expect(channel.coordinationMatrix).toBeDefined();
154
+ const deferredID = await api.OpenModelStreamed(data, { ...SETTINGS, DEFER_GEOMETRY: true });
155
+ api.StreamAllMeshes(deferredID, () => { });
156
+ const classicCoordination = api.GetCoordinationMatrix(classicID);
157
+ const deferredCoordination = api.GetCoordinationMatrix(deferredID);
158
+ expect(deferredCoordination).toEqual(classicCoordination);
159
+ api.CloseModel(classicID);
160
+ api.CloseModel(deferredID);
161
+ }, 240000);
162
+ test("ON_PREVIEW_MESH on a deferred streamed open never breaks the durable path", async () => {
163
+ const classicID = api.OpenModel(data, SETTINGS);
164
+ const classic = classicInstances(classicID);
165
+ const payloads = [];
166
+ const deferredID = await api.OpenModelStreamed(data, {
167
+ ...SETTINGS,
168
+ DEFER_GEOMETRY: true,
169
+ ON_PREVIEW_MESH: (mesh) => payloads.push(mesh),
170
+ });
171
+ expect(deferredID).toBeGreaterThanOrEqual(0);
172
+ // index.ifc parses inside one cooperative slice, so the timer-driven
173
+ // channel usually never fires — the contract here is that its presence
174
+ // changes nothing about the durable pump's output.
175
+ const drained = new Map();
176
+ api.StreamAllMeshes(deferredID, (mesh) => {
177
+ drained.set(mesh.expressID, (drained.get(mesh.expressID) ?? 0) + mesh.geometries.size());
178
+ });
179
+ expect(drained.size).toBe(classic.size);
180
+ for (const [expressID, list] of classic) {
181
+ expect(drained.get(expressID)).toBe(list.length);
182
+ }
183
+ api.CloseModel(classicID);
184
+ api.CloseModel(deferredID);
185
+ }, 240000);
186
+ test("a throwing prefix build retires the attempt, not the channel", () => {
187
+ // Mid-parse prefixes can be structurally incomplete and the adapter's
188
+ // generation build can THROW (AP214's assembly-tree prep does on
189
+ // dangling references — this killed the whole STEP preview). The
190
+ // channel must swallow the attempt and succeed on a later, larger
191
+ // prefix. The sink is complete here, so growth is simulated by
192
+ // inflating the reported record count past the retry gate.
193
+ const sink = buildSink();
194
+ const realRecords = sink.topLevelCount;
195
+ let reportedRecords = realRecords;
196
+ const growingSink = {
197
+ get topLevelCount() {
198
+ return reportedRecords;
199
+ },
200
+ snapshot: () => sink.snapshot(),
201
+ };
202
+ let buildAttempts = 0;
203
+ const inner = ifcPreviewAdapter();
204
+ const flakyAdapter = {
205
+ buildGeneration: (source, wasm, columns) => {
206
+ if (buildAttempts++ === 0) {
207
+ throw new Error("structurally incomplete prefix");
208
+ }
209
+ return inner.buildGeneration(source, wasm, columns);
210
+ },
211
+ };
212
+ const payloads = [];
213
+ const channel = new StreamedPreviewChannel(data, conwayGeometry, growingSink, flakyAdapter, true, (mesh) => payloads.push(mesh), void 0, void 0, 1);
214
+ // First drain: the build throws — no payloads, but the channel
215
+ // survives the attempt.
216
+ channel.drainForTest();
217
+ expect(buildAttempts).toBe(1);
218
+ expect(payloads.length).toBe(0);
219
+ // Same record count: the failure gate must hold the retry.
220
+ channel.drainForTest();
221
+ expect(buildAttempts).toBe(1);
222
+ // The index "grows" past the gate: the retry builds and drains fully.
223
+ reportedRecords = realRecords * 4;
224
+ channel.drainForTest();
225
+ expect(buildAttempts).toBe(2);
226
+ expect(payloads.length).toBeGreaterThan(0);
227
+ }, 240000);
228
+ test("retryEmptyUnits re-runs empty units on later generations", () => {
229
+ // AP214-style schema: the unit list is fixed up front but the
230
+ // geometry units reference arrives later in the file. The channel
231
+ // must re-run units that captured nothing against each richer
232
+ // generation, and stop retrying a unit once it captures.
233
+ const UNIT_COUNT = 3;
234
+ const runsPerGeneration = [];
235
+ let reportedRecords = 2048;
236
+ const fakeSink = {
237
+ get topLevelCount() {
238
+ return reportedRecords;
239
+ },
240
+ snapshot: () => ({}),
241
+ };
242
+ const disposed = [];
243
+ const makeGeneration = (generationIndex) => {
244
+ const runs = [];
245
+ runsPerGeneration.push(runs);
246
+ return {
247
+ // Empty scene: units "execute" but never capture, so no unit
248
+ // ever completes and every generation re-runs all of them.
249
+ scene: { *walk() { } },
250
+ unitCount: UNIT_COUNT,
251
+ linearScalingFactor: 1,
252
+ runUnits: (from) => {
253
+ runs.push(from);
254
+ return 1;
255
+ },
256
+ geometryExpressID: () => void 0,
257
+ recenter: false,
258
+ dispose: () => disposed.push(generationIndex),
259
+ };
260
+ };
261
+ let generationIndex = 0;
262
+ const adapter = {
263
+ retryEmptyUnits: true,
264
+ buildGeneration: () => makeGeneration(generationIndex++),
265
+ };
266
+ const channel = new StreamedPreviewChannel(data, conwayGeometry, fakeSink, adapter, false, () => { }, void 0, void 0, 1);
267
+ const forceTick = () => {
268
+ /* eslint-disable @typescript-eslint/no-explicit-any */
269
+ channel.lastInlineTick_ = 0;
270
+ channel.tickIntervalMs_ = 0;
271
+ // Lift the per-tick wall-clock budget too. The assertions below count
272
+ // exactly which units ran in a tick, and against the real 25ms budget
273
+ // that is a coin flip on a loaded runner — this expected [0,1,2] and
274
+ // got [0,1] in CI while passing locally.
275
+ channel.tickBudgetMs_ = Number.MAX_SAFE_INTEGER;
276
+ /* eslint-enable @typescript-eslint/no-explicit-any */
277
+ channel.maybeTickInline();
278
+ };
279
+ // Generation 1: all units run once (none capture).
280
+ forceTick();
281
+ expect(runsPerGeneration[0]).toEqual([0, 1, 2]);
282
+ // Same record count: growth-gated, no rebuild, no re-runs.
283
+ forceTick();
284
+ expect(runsPerGeneration.length).toBe(1);
285
+ expect(runsPerGeneration[0]).toEqual([0, 1, 2]);
286
+ // Records double: a fresh generation re-runs every empty unit and
287
+ // the outgoing generation is disposed.
288
+ reportedRecords *= 4;
289
+ forceTick();
290
+ expect(runsPerGeneration.length).toBe(2);
291
+ expect(runsPerGeneration[1]).toEqual([0, 1, 2]);
292
+ expect(disposed).toContain(0);
293
+ channel.stop();
294
+ }, 240000);
295
+ test("a product whose placement is beyond the prefix defers instead of extracting unplaced", () => {
296
+ // Revit writes placements near the end of the file, so a mid-parse
297
+ // prefix can hold a product and its geometry while the product's
298
+ // IFCLOCALPLACEMENT is still unparsed. Lenient reads null that
299
+ // dangling reference — indistinguishable from "no placement" — and
300
+ // the product extracted at the origin: on a georeferenced model the
301
+ // preview payloads then sat a whole site-offset from the model
302
+ // (Share#1744, Snowdon door #5014, 88 payloads ~425km out).
303
+ //
304
+ // Model the file shape directly: move one product's placement
305
+ // record to the end of the data section (record order carries no
306
+ // meaning in STEP) and snapshot the prefix just before it.
307
+ const DEFERRED_PRODUCT = 396;
308
+ const PLACEMENT_RECORD = "#334=";
309
+ const text = new TextDecoder().decode(data);
310
+ const lines = text.split("\n");
311
+ const placementIndex = lines.findIndex((line) => line.startsWith(PLACEMENT_RECORD));
312
+ expect(placementIndex).toBeGreaterThanOrEqual(0);
313
+ const [placementLine] = lines.splice(placementIndex, 1);
314
+ let endsecIndex = -1;
315
+ for (let where = lines.length - 1; where >= 0; --where) {
316
+ if (lines[where].startsWith("ENDSEC")) {
317
+ endsecIndex = where;
318
+ break;
319
+ }
320
+ }
321
+ expect(endsecIndex).toBeGreaterThanOrEqual(0);
322
+ lines.splice(endsecIndex, 0, placementLine);
323
+ const reordered = new TextEncoder().encode(lines.join("\n"));
324
+ const totalRecords = buildSink(void 0, reordered).topLevelCount;
325
+ // The moved placement is the final record: a prefix of every record
326
+ // but the last holds the product + geometry, not the placement.
327
+ let prefix;
328
+ const fullColumns = buildSink((inner) => ({
329
+ pushTopLevel: (entry) => {
330
+ inner.pushTopLevel(entry);
331
+ if (inner.topLevelCount === totalRecords - 1) {
332
+ prefix = inner.snapshot();
333
+ }
334
+ },
335
+ reset: () => inner.reset(),
336
+ }), reordered).finalize();
337
+ expect(prefix).toBeDefined();
338
+ // Entity expressID -> parent native transforms of its walked
339
+ // instances, for one generation over the given columns.
340
+ const placedInstances = (bytes, columns) => {
341
+ const generation = ifcPreviewAdapter().buildGeneration(bytes, conwayGeometry, columns);
342
+ expect(generation).toBeDefined();
343
+ generation.runUnits(0, generation.unitCount);
344
+ const instances = new Map();
345
+ for (const walked of generation.scene.walk()) {
346
+ const [, nativeTransform, , , entity] = walked;
347
+ if (entity?.expressID === void 0) {
348
+ continue;
349
+ }
350
+ const list = instances.get(entity.expressID) ?? [];
351
+ list.push(nativeTransform !== void 0 ? [...nativeTransform.getValues()] : []);
352
+ instances.set(entity.expressID, list);
353
+ }
354
+ generation.dispose();
355
+ return instances;
356
+ };
357
+ const prefixInstances = placedInstances(reordered, prefix);
358
+ // Other products still preview from the prefix...
359
+ expect(prefixInstances.size).toBeGreaterThan(0);
360
+ // ...but the dangling-placement product emitted NOTHING. Before the
361
+ // fix it extracted with an identity parent — these are exactly the
362
+ // mis-placed payloads Share#1744 chased.
363
+ expect(prefixInstances.has(DEFERRED_PRODUCT)).toBe(false);
364
+ // A full-file prefix extracts it, placed identically to the
365
+ // original record order — deferral changes WHEN the product
366
+ // extracts, never WHERE.
367
+ const fullInstances = placedInstances(reordered, fullColumns);
368
+ const reorderedTransforms = fullInstances.get(DEFERRED_PRODUCT);
369
+ expect(reorderedTransforms).toBeDefined();
370
+ expect(reorderedTransforms.length).toBeGreaterThan(0);
371
+ expect(reorderedTransforms[0].length).toBe(16);
372
+ const originalInstances = placedInstances(data, buildSink().finalize());
373
+ const originalTransforms = originalInstances.get(DEFERRED_PRODUCT);
374
+ expect(originalTransforms).toBeDefined();
375
+ expect(reorderedTransforms.length).toBe(originalTransforms.length);
376
+ for (let where = 0; where < originalTransforms.length; ++where) {
377
+ for (let component = 0; component < 16; ++component) {
378
+ expect(reorderedTransforms[where][component])
379
+ .toBeCloseTo(originalTransforms[where][component], 10);
380
+ }
381
+ }
382
+ }, 240000);
383
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ifc_api_preview_coordination.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ifc_api_preview_coordination.test.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/ifc_api_preview_coordination.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,124 @@
1
+ /* eslint-disable no-magic-numbers, dot-notation */
2
+ // Adopted preview-channel coordination frames must be validated against
3
+ // the durable walk's first geometry (Share#1634): a model can carry
4
+ // geometry in more than one frame, so a preview anchored on a
5
+ // local-scale unit hands the deferred pump a ~identity frame and the
6
+ // georeferenced body streams out raw. The deferred pump now re-derives
7
+ // from its own first geometry when the adopted frame leaves it beyond
8
+ // the large-coordinate budget.
9
+ //
10
+ // The adoption is injected directly (tiny fixtures parse in one tick,
11
+ // so the parse-time preview channel never fires on them); the injected
12
+ // identity frame is exactly what a wrong-frame preview anchor produces.
13
+ import * as fs from "fs";
14
+ import { beforeAll, describe, expect, test } from "@jest/globals";
15
+ import { LARGE_COORDINATE_BUDGET_M } from "./coordination_f64.js";
16
+ import { IfcAPI } from "./ifc_api.js";
17
+ const SETTINGS = {
18
+ COORDINATE_TO_ORIGIN: true,
19
+ USE_FAST_BOOLS: true,
20
+ DEFER_GEOMETRY: true,
21
+ };
22
+ const IDENTITY = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
23
+ let api;
24
+ let georeferenced;
25
+ let local;
26
+ /**
27
+ * Pump a deferred model to completion and collect every placement
28
+ * translation.
29
+ *
30
+ * @param modelID The deferred model.
31
+ * @return {number[][]} One [x, y, z] per placed geometry.
32
+ */
33
+ function pumpTranslations(modelID) {
34
+ const translations = [];
35
+ for (;;) {
36
+ const batch = [];
37
+ const { extracted, remaining } = api.ExtractGeometryBatch(modelID, 4, (mesh) => batch.push(mesh));
38
+ for (const mesh of batch) {
39
+ for (let where = 0; where < mesh.geometries.size(); ++where) {
40
+ const placed = mesh.geometries.get(where);
41
+ translations.push([
42
+ placed.flatTransformation[12],
43
+ placed.flatTransformation[13],
44
+ placed.flatTransformation[14],
45
+ ]);
46
+ }
47
+ }
48
+ if (remaining === 0 || extracted === 0) {
49
+ break;
50
+ }
51
+ }
52
+ return translations;
53
+ }
54
+ /**
55
+ * @param translations Placement translations.
56
+ * @return {number} Largest absolute component.
57
+ */
58
+ function maxComponent(translations) {
59
+ return translations.reduce((max, t) => Math.max(max, ...t.map(Math.abs)), 0);
60
+ }
61
+ /**
62
+ * Simulate a preview channel that anchored in the wrong frame: adopt an
63
+ * identity coordination exactly the way createDeferred does.
64
+ *
65
+ * @param modelID The deferred model.
66
+ */
67
+ function injectIdentityPreviewFrame(modelID) {
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ const proxy = api.models.get(modelID);
70
+ expect(proxy).toBeDefined();
71
+ proxy["demandCoordination_"] = [...IDENTITY];
72
+ proxy["_isCoordinated"] = true;
73
+ proxy["demandCoordinationFromPreview_"] = true;
74
+ }
75
+ beforeAll(async () => {
76
+ api = new IfcAPI();
77
+ await api.Init();
78
+ georeferenced = new Uint8Array(fs.readFileSync("data/index_georeferenced.ifc"));
79
+ local = new Uint8Array(fs.readFileSync("data/index.ifc"));
80
+ }, 120000);
81
+ describe("deferred pump preview-frame validation (Share#1634)", () => {
82
+ test("wrong-frame adopted coordination is re-derived on a georeferenced model", async () => {
83
+ // Control: no preview involvement — the pump derives its own frame.
84
+ const controlID = await api.OpenModelStreamed(georeferenced, { ...SETTINGS });
85
+ const control = pumpTranslations(controlID);
86
+ expect(control.length).toBeGreaterThan(0);
87
+ expect(maxComponent(control)).toBeLessThan(LARGE_COORDINATE_BUDGET_M);
88
+ // Explicit applied-frame report (Share#1634 acceptance): the real
89
+ // recenter offset — while GetCoordinationMatrix keeps its classic
90
+ // identity contract for assembled-model stamping.
91
+ const applied = api.GetAppliedCoordinationMatrix(controlID);
92
+ expect(Math.max(...applied.map(Math.abs)))
93
+ .toBeGreaterThan(LARGE_COORDINATE_BUDGET_M);
94
+ expect(api.GetCoordinationMatrix(controlID)).toEqual(IDENTITY);
95
+ // Adopting an identity frame (wrong-frame preview anchor) must not
96
+ // leave the body raw: the first durable geometry fails the budget
97
+ // check and the frame re-derives.
98
+ const adoptedID = await api.OpenModelStreamed(georeferenced, { ...SETTINGS });
99
+ injectIdentityPreviewFrame(adoptedID);
100
+ const adopted = pumpTranslations(adoptedID);
101
+ expect(adopted.length).toEqual(control.length);
102
+ expect(maxComponent(adopted)).toBeLessThan(LARGE_COORDINATE_BUDGET_M);
103
+ for (let where = 0; where < control.length; ++where) {
104
+ expect(adopted[where][0]).toBeCloseTo(control[where][0], 6);
105
+ expect(adopted[where][1]).toBeCloseTo(control[where][1], 6);
106
+ expect(adopted[where][2]).toBeCloseTo(control[where][2], 6);
107
+ }
108
+ }, 120000);
109
+ test("a within-budget adopted frame is kept (no false-positive re-derive)", async () => {
110
+ // On a local-scale model an identity frame is a VALID preview
111
+ // frame — validation must keep it, preserving preview/durable
112
+ // agreement, rather than re-deriving to the first-geometry anchor.
113
+ const adoptedID = await api.OpenModelStreamed(local, { ...SETTINGS });
114
+ injectIdentityPreviewFrame(adoptedID);
115
+ const adopted = pumpTranslations(adoptedID);
116
+ expect(adopted.length).toBeGreaterThan(0);
117
+ expect(maxComponent(adopted)).toBeLessThan(LARGE_COORDINATE_BUDGET_M);
118
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
+ const proxy = api.models.get(adoptedID);
120
+ // Frame survived untouched: still exactly the injected identity.
121
+ expect([...proxy["demandCoordination_"]]).toEqual(IDENTITY);
122
+ expect(proxy["demandCoordinationFromPreview_"]).toBe(false);
123
+ }, 120000);
124
+ });