@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
@@ -1,6 +1,11 @@
1
1
  import StepParser from "../step/parsing/step_parser.js";
2
2
  import EntitTypesIfcSearch from "./ifc4_gen/entity_types_search.gen.js";
3
3
  import IfcStepModel from "./ifc_step_model.js";
4
+ import { buildColumnarIndexStreaming, buildColumnarIndexStreamingAsync, } from "../step/parsing/streaming_index_builder.js";
5
+ import { WindowedStepBufferProvider, } from "../step/step_buffer_provider.js";
6
+ /** Default moving-window size for the streaming index build (1 MiB). */
7
+ // eslint-disable-next-line no-magic-numbers
8
+ const DEFAULT_STREAM_POOL_BYTES = 1024 * 1024;
4
9
  /**
5
10
  * Parser for taking IFC file serialized in step and turning them into a lazily parsed model.
6
11
  */
@@ -36,6 +41,65 @@ class IfcStepParser extends StepParser {
36
41
  const [itemIndex, parseResult] = await this.parseDataBlockAsync(input, onProgress);
37
42
  return [parseResult, new IfcStepModel(input.buffer, itemIndex.elements)];
38
43
  }
44
+ /**
45
+ * Build a model by streaming the source through a bounded moving window
46
+ * (see buildIndexStreaming / M0) rather than parsing one resident buffer,
47
+ * then backing the model with a windowed provider over `store` — so the
48
+ * source is never held fully resident in the JS heap.
49
+ *
50
+ * `source` serves the parse (synchronous windowed reads — on a worker this
51
+ * is an OPFS sync-access handle; in node/tests a file descriptor or buffer)
52
+ * and `store` serves the model's post-parse property access (asynchronous
53
+ * windowed reads paged in on demand — OPFS `File.slice()` in the browser).
54
+ * Both view the same file bytes, so the file-absolute addresses the index
55
+ * records resolve identically through either.
56
+ *
57
+ * NOTE (M1 scope): this delivers the bounded-memory *parse*. Synchronous
58
+ * geometry extraction still needs its record ranges resident — as after
59
+ * `spillSourceToExternalStore` — so a caller that extracts geometry must
60
+ * `ensureResident` first (demand-driven geometry is M3). Property / index
61
+ * access works directly via the async surfaces.
62
+ *
63
+ * @param source Synchronous byte source feeding the streaming parse.
64
+ * @param store Async external store backing the windowed model.
65
+ * @param opts Optional window sizing: `pool` (parse window),
66
+ * `chunkBytes` / `maxResidentChunks` (model window).
67
+ * @return {[ParseResult, IfcStepModel | undefined]} The parse result and
68
+ * the windowed model.
69
+ */
70
+ parseStreamToModel(source, store, opts) {
71
+ if (store.byteLength !== source.byteLength) {
72
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match ` +
73
+ `source byteLength ${source.byteLength}`);
74
+ }
75
+ // Columnar build (M7): the index goes straight into SoA columns — the
76
+ // per-record object phase never exists, so peak heap is window + columns.
77
+ const { columns, result } = buildColumnarIndexStreaming(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES);
78
+ const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
79
+ return [result, new IfcStepModel(void 0, columns, provider)];
80
+ }
81
+ /**
82
+ * Cooperative twin of {@link parseStreamToModel}: the index build
83
+ * yields to the event loop and can fill windows from an async
84
+ * {@link ReadableByteSource} (an OPFS `File.slice()` store). The
85
+ * model is still windowed — geometry extract must
86
+ * `ensureResident` first.
87
+ *
88
+ * @param source Sync or async byte source feeding the parse.
89
+ * @param store Async external store backing the windowed model.
90
+ * @param opts Optional window sizing plus parse progress.
91
+ * @return {Promise<[ParseResult, IfcStepModel | undefined]>} The
92
+ * parse result and the windowed model.
93
+ */
94
+ async parseStreamToModelAsync(source, store, opts) {
95
+ if (store.byteLength !== source.byteLength) {
96
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match ` +
97
+ `source byteLength ${source.byteLength}`);
98
+ }
99
+ const { columns, result } = await buildColumnarIndexStreamingAsync(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES, void 0, opts?.onProgress);
100
+ const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
101
+ return [result, new IfcStepModel(void 0, columns, provider)];
102
+ }
39
103
  }
40
104
  /**
41
105
  * An easily accessible and re-usable instance of the parser.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ifc_stream_model.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ifc_stream_model.test.d.ts","sourceRoot":"","sources":["../../../src/ifc/ifc_stream_model.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,70 @@
1
+ /* eslint-disable no-magic-numbers */
2
+ // M1 core: a model built by streaming the source through a bounded window
3
+ // (parseStreamToModel) must decode records byte-identically to the resident
4
+ // parse — reading them on demand through the windowed provider after
5
+ // ensureResident, with the source never held fully resident.
6
+ import * as fs from "fs";
7
+ import { beforeAll, describe, expect, test } from "@jest/globals";
8
+ import ParsingBuffer from "../parsing/parsing_buffer.js";
9
+ import IfcStepParser from "./ifc_step_parser.js";
10
+ import { BufferByteSource } from "../step/parsing/byte_source.js";
11
+ import { InMemoryStepByteStore } from "../step/step_buffer_provider.js";
12
+ import { ParseResult } from "../step/parsing/step_parser.js";
13
+ import { IfcRoot } from "./ifc4_gen/index.js";
14
+ let bytes;
15
+ /**
16
+ * Decode every IfcRoot-derived entity's GlobalId + Name from a model into a
17
+ * stable map — the attributes are read from the record bytes, so this
18
+ * exercises the actual byte path (resident buffer vs windowed provider).
19
+ *
20
+ * @param model The model to read from.
21
+ * @return {Map<number, string>} expressID → "GlobalId|Name".
22
+ */
23
+ function rootAttributes(model) {
24
+ const out = new Map();
25
+ for (const expressID of model.expressIDsOfTypes(IfcRoot)) {
26
+ const entity = model.getElementByExpressID(expressID);
27
+ if (entity === void 0) {
28
+ continue;
29
+ }
30
+ const globalId = typeof entity.GlobalId === "string" ? entity.GlobalId : "";
31
+ const name = typeof entity.Name === "string" ? entity.Name : "";
32
+ out.set(expressID, `${globalId}|${name}`);
33
+ }
34
+ return out;
35
+ }
36
+ beforeAll(() => {
37
+ bytes = new Uint8Array(fs.readFileSync("data/index.ifc"));
38
+ });
39
+ describe("parseStreamToModel", () => {
40
+ test("streamed windowed model decodes records identically to the resident parse", async () => {
41
+ // Resident ground truth.
42
+ const residentInput = new ParsingBuffer(bytes);
43
+ IfcStepParser.Instance.parseHeader(residentInput);
44
+ const [, residentModel] = IfcStepParser.Instance.parseDataToModel(residentInput);
45
+ const expected = rootAttributes(residentModel);
46
+ expect(expected.size).toBeGreaterThan(10);
47
+ // Streamed: tiny parse window forces slides; tiny model chunks force
48
+ // paging. Same bytes behind both the sync source and the async store.
49
+ const [result, streamModel] = IfcStepParser.Instance.parseStreamToModel(new BufferByteSource(bytes), new InMemoryStepByteStore(bytes), { pool: 4 * 1024, chunkBytes: 512, maxResidentChunks: 3 });
50
+ expect(result).toBe(ParseResult.COMPLETE);
51
+ expect(streamModel.isSourceExternal).toBe(true);
52
+ // Page each record in on demand, then decode; must match resident.
53
+ const actual = new Map();
54
+ for (const expressID of streamModel.expressIDsOfTypes(IfcRoot)) {
55
+ await streamModel.ensureResidentByExpressID(expressID);
56
+ const entity = streamModel.getElementByExpressID(expressID);
57
+ if (entity === void 0) {
58
+ continue;
59
+ }
60
+ const globalId = typeof entity.GlobalId === "string" ? entity.GlobalId : "";
61
+ const name = typeof entity.Name === "string" ? entity.Name : "";
62
+ actual.set(expressID, `${globalId}|${name}`);
63
+ }
64
+ expect(actual).toEqual(expected);
65
+ }, 60000);
66
+ test("rejects a store whose size does not match the source", () => {
67
+ expect(() => IfcStepParser.Instance.parseStreamToModel(new BufferByteSource(bytes), new InMemoryStepByteStore(bytes.subarray(0, bytes.length - 1))))
68
+ .toThrow(/does not match/);
69
+ });
70
+ });
@@ -0,0 +1,131 @@
1
+ import { ByteSource, ReadableByteSource } from "../step/parsing/byte_source.js";
2
+ import { ColumnarIndexSink, StepIndexColumns } from "../step/parsing/columnar_index.js";
3
+ import { RecordEventHandler } from "../step/parsing/record_event.js";
4
+ import { StreamingIndexStats } from "../step/parsing/streaming_index_builder.js";
5
+ import { ParseResult, StepHeader } from "../step/parsing/step_parser.js";
6
+ import { StepExternalByteStore } from "../step/step_buffer_provider.js";
7
+ import EntityTypesIfc from "./ifc4_gen/entity_types_ifc.gen.js";
8
+ import { PrefixTypeIndex } from "../step/parsing/prefix_type_index.js";
9
+ import IfcStepModel from "./ifc_step_model.js";
10
+ /**
11
+ * Options for a streamed IFC open. All optional; defaults suit a browser
12
+ * worker over an OPFS-backed store.
13
+ */
14
+ export interface StreamedIfcOpenOptions {
15
+ /** Parse window size in bytes (default 1 MiB). */
16
+ pool?: number;
17
+ /** Windowed provider chunk size (default: provider's). */
18
+ chunkBytes?: number;
19
+ /** Windowed provider LRU cap in chunks (default: provider's). */
20
+ maxResidentChunks?: number;
21
+ /**
22
+ * Live per-record event — the M2 seam for incremental consumers (type
23
+ * index, roots, cross-refs, names skeleton) that run while the model is
24
+ * still parsing. Must be synchronous and cheap; see
25
+ * {@link RecordEventHandler} for the payload and the window-lifetime rule
26
+ * on the record bytes it hands over.
27
+ */
28
+ onRecordIndexed?: RecordEventHandler<EntityTypesIfc>;
29
+ /**
30
+ * Caller-owned index sink. Pass one to hold the columns *while* the parse
31
+ * runs — the seam a prefix-derived consumer reads
32
+ * ({@link ifcPrefixTypeIndex}). Without it the columns only exist once the
33
+ * open returns, which is too late for anything mid-parse.
34
+ */
35
+ indexSink?: ColumnarIndexSink<EntityTypesIfc>;
36
+ }
37
+ /**
38
+ * The result of a streamed IFC open: the windowed-source model plus the
39
+ * artifacts a consumer needs around it.
40
+ */
41
+ export interface StreamedIfcOpen {
42
+ /** The model over the windowed source (undefined if the parse failed). */
43
+ model: IfcStepModel | undefined;
44
+ /** The parse result. */
45
+ result: ParseResult;
46
+ /** The STEP header (available even on some failed parses). */
47
+ header: StepHeader;
48
+ /**
49
+ * The columnar index the model was built from. Hand to
50
+ * `serializeIndexSidecarFromColumns` (with a source hash) to produce the
51
+ * revisit sidecar — the columns ARE the sidecar payload (M7 identity).
52
+ */
53
+ columns: StepIndexColumns<EntityTypesIfc>;
54
+ /** Window diagnostics from the streaming build. */
55
+ stats: StreamingIndexStats;
56
+ }
57
+ /**
58
+ * Open an IFC model from a streamed source with a **fixed-memory parse**
59
+ * (the release-facing Phase B API; composes M0/M1a/M7):
60
+ *
61
+ * - the index builds through a moving window over `source` — the source is
62
+ * never resident in the JS heap, and the index is columnar from birth
63
+ * (no per-record object phase);
64
+ * - the model reads source bytes on demand through a windowed LRU provider
65
+ * over `store` (`ensureResidentByLocalID`/`ByExpressID` page ranges in
66
+ * before synchronous reads — see `DemandResidencyPump` for the demand
67
+ * orchestration).
68
+ *
69
+ * The typical browser wiring: a worker streams the network body **through**
70
+ * to OPFS while feeding the same bytes to `source`; `store` reads back from
71
+ * OPFS. `source.byteLength` and `store.byteLength` must agree.
72
+ *
73
+ * @param source The sequential parse source.
74
+ * @param store The random-access store the model reads from afterwards.
75
+ * @param options See {@link StreamedIfcOpenOptions}.
76
+ * @return {StreamedIfcOpen} The model + header, columns, and diagnostics.
77
+ */
78
+ export declare function openStreamedIfcModel(source: ByteSource, store: StepExternalByteStore, options?: StreamedIfcOpenOptions): StreamedIfcOpen;
79
+ /**
80
+ * A type index over the IFC records parsed so far, paired with the schema's
81
+ * production indexer — the composed form of {@link PrefixTypeIndex} that a
82
+ * caller needs, since the index is only useful mid-parse if it reads the same
83
+ * live sink the open is filling.
84
+ *
85
+ * ```ts
86
+ * const indexSink = new ColumnarIndexSink<EntityTypesIfc>()
87
+ * const types = ifcPrefixTypeIndex( indexSink )
88
+ * const open = await openStreamedIfcModelAsync( source, store, {
89
+ * indexSink,
90
+ * onProgress: () => reveal( types.expressIDsOfTypes( IfcProduct ) ),
91
+ * } )
92
+ * ```
93
+ *
94
+ * @param sink The sink passed to the open as `indexSink`.
95
+ * @param options Rebuild pacing (see {@link PrefixTypeIndex}).
96
+ * @param options.growthFactor Record growth before a query rebuilds.
97
+ * @param options.minimumRecords Count below which pacing is skipped.
98
+ * @return {PrefixTypeIndex<EntityTypesIfc>} The index over that sink.
99
+ */
100
+ export declare function ifcPrefixTypeIndex(sink: ColumnarIndexSink<EntityTypesIfc>, options?: {
101
+ growthFactor?: number;
102
+ minimumRecords?: number;
103
+ }): PrefixTypeIndex<EntityTypesIfc>;
104
+ /**
105
+ * Cooperative twin of {@link openStreamedIfcModel}: the index build
106
+ * yields to the event loop and can fill windows from an async
107
+ * {@link ReadableByteSource}. Pass a {@link StoreByteSource} wrapping
108
+ * `store` to parse a file that is already in OPFS without ever
109
+ * holding it as one `ArrayBuffer`.
110
+ *
111
+ * @param source Sync or async parse source.
112
+ * @param store The random-access store the model reads from afterwards.
113
+ * @param options See {@link StreamedIfcOpenOptions} plus `onProgress`.
114
+ * @return {Promise<StreamedIfcOpen>} The model + header, columns, diagnostics.
115
+ */
116
+ export declare function openStreamedIfcModelAsync(source: ReadableByteSource, store: StepExternalByteStore, options?: StreamedIfcOpenOptions & {
117
+ onProgress?: (absoluteByteCursor: number) => void;
118
+ }): Promise<StreamedIfcOpen>;
119
+ /**
120
+ * Open a windowed IFC model from a store alone — parse windows and
121
+ * post-parse reads share `store`. This is the M1b embedder entry for
122
+ * a file already sitting in OPFS.
123
+ *
124
+ * @param store The source of truth for the file bytes.
125
+ * @param options See {@link openStreamedIfcModelAsync}.
126
+ * @return {Promise<StreamedIfcOpen>} The model + header, columns, diagnostics.
127
+ */
128
+ export declare function openStreamedIfcModelFromStore(store: StepExternalByteStore, options?: StreamedIfcOpenOptions & {
129
+ onProgress?: (absoluteByteCursor: number) => void;
130
+ }): Promise<StreamedIfcOpen>;
131
+ //# sourceMappingURL=ifc_stream_open.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ifc_stream_open.d.ts","sourceRoot":"","sources":["../../../src/ifc/ifc_stream_open.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAmB,MAAM,6BAA6B,CAAA;AAC7F,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,EAGL,mBAAmB,EACpB,MAAM,yCAAyC,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AACrE,OAAO,EACL,qBAAqB,EAEtB,MAAM,8BAA8B,CAAA;AACrC,OAAO,cAAuC,MAAM,iCAAiC,CAAA;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AAEnE,OAAO,YAAY,MAAM,kBAAkB,CAAA;AAI3C;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IAErC,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB,iEAAiE;IACjE,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAE1B;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAA;IAEpD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAA;CAC9C;AAGD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAE9B,0EAA0E;IAC1E,KAAK,EAAE,YAAY,GAAG,SAAS,CAAA;IAE/B,wBAAwB;IACxB,MAAM,EAAE,WAAW,CAAA;IAEnB,8DAA8D;IAC9D,MAAM,EAAE,UAAU,CAAA;IAElB;;;;OAIG;IACH,OAAO,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAA;IAEzC,mDAAmD;IACnD,KAAK,EAAE,mBAAmB,CAAA;CAC3B;AAOD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAChC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,qBAAqB,EAC5B,OAAO,CAAC,EAAE,sBAAsB,GAAI,eAAe,CA6BtD;AAGD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAC9B,IAAI,EAAE,iBAAiB,CAAC,cAAc,CAAC,EACvC,OAAO,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5D,eAAe,CAAC,cAAc,CAAC,CAIlC;AAGD;;;;;;;;;;;GAWG;AACH,wBAAsB,yBAAyB,CAC3C,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,qBAAqB,EAC5B,OAAO,CAAC,EAAE,sBAAsB,GAAG;IACjC,UAAU,CAAC,EAAE,CAAE,kBAAkB,EAAE,MAAM,KAAM,IAAI,CAAA;CACpD,GAAI,OAAO,CAAC,eAAe,CAAC,CA+BhC;AAGD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CACzC,KAAK,EAAE,qBAAqB,EAC5B,OAAO,CAAC,EAAE,sBAAsB,GAAG;IACjC,UAAU,CAAC,EAAE,CAAE,kBAAkB,EAAE,MAAM,KAAM,IAAI,CAAA;CACpD,GAAI,OAAO,CAAC,eAAe,CAAC,CAGhC"}
@@ -0,0 +1,116 @@
1
+ import { StoreByteSource } from "../step/parsing/byte_source.js";
2
+ import { buildColumnarIndexStreaming, buildColumnarIndexStreamingAsync, } from "../step/parsing/streaming_index_builder.js";
3
+ import { ParseResult } from "../step/parsing/step_parser.js";
4
+ import { WindowedStepBufferProvider, } from "../step/step_buffer_provider.js";
5
+ import { EntityTypesIfcCount } from "./ifc4_gen/entity_types_ifc.gen.js";
6
+ import { PrefixTypeIndex } from "../step/parsing/prefix_type_index.js";
7
+ import { StepTypeIndexer } from "../step/indexing/step_type_indexer.js";
8
+ import IfcStepModel from "./ifc_step_model.js";
9
+ import IfcStepParser from "./ifc_step_parser.js";
10
+ // eslint-disable-next-line no-magic-numbers
11
+ const DEFAULT_STREAM_POOL_BYTES = 1024 * 1024;
12
+ /**
13
+ * Open an IFC model from a streamed source with a **fixed-memory parse**
14
+ * (the release-facing Phase B API; composes M0/M1a/M7):
15
+ *
16
+ * - the index builds through a moving window over `source` — the source is
17
+ * never resident in the JS heap, and the index is columnar from birth
18
+ * (no per-record object phase);
19
+ * - the model reads source bytes on demand through a windowed LRU provider
20
+ * over `store` (`ensureResidentByLocalID`/`ByExpressID` page ranges in
21
+ * before synchronous reads — see `DemandResidencyPump` for the demand
22
+ * orchestration).
23
+ *
24
+ * The typical browser wiring: a worker streams the network body **through**
25
+ * to OPFS while feeding the same bytes to `source`; `store` reads back from
26
+ * OPFS. `source.byteLength` and `store.byteLength` must agree.
27
+ *
28
+ * @param source The sequential parse source.
29
+ * @param store The random-access store the model reads from afterwards.
30
+ * @param options See {@link StreamedIfcOpenOptions}.
31
+ * @return {StreamedIfcOpen} The model + header, columns, and diagnostics.
32
+ */
33
+ export function openStreamedIfcModel(source, store, options) {
34
+ if (store.byteLength !== source.byteLength) {
35
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match ` +
36
+ `source byteLength ${source.byteLength}`);
37
+ }
38
+ const { header, columns, result, stats } = buildColumnarIndexStreaming(source, IfcStepParser.Instance, options?.pool ?? DEFAULT_STREAM_POOL_BYTES, options?.onRecordIndexed, options?.indexSink);
39
+ if (result !== ParseResult.COMPLETE) {
40
+ return { model: void 0, result, header, columns, stats };
41
+ }
42
+ const provider = new WindowedStepBufferProvider(store, options?.chunkBytes, options?.maxResidentChunks);
43
+ return {
44
+ model: new IfcStepModel(void 0, columns, provider),
45
+ result,
46
+ header,
47
+ columns,
48
+ stats,
49
+ };
50
+ }
51
+ /**
52
+ * A type index over the IFC records parsed so far, paired with the schema's
53
+ * production indexer — the composed form of {@link PrefixTypeIndex} that a
54
+ * caller needs, since the index is only useful mid-parse if it reads the same
55
+ * live sink the open is filling.
56
+ *
57
+ * ```ts
58
+ * const indexSink = new ColumnarIndexSink<EntityTypesIfc>()
59
+ * const types = ifcPrefixTypeIndex( indexSink )
60
+ * const open = await openStreamedIfcModelAsync( source, store, {
61
+ * indexSink,
62
+ * onProgress: () => reveal( types.expressIDsOfTypes( IfcProduct ) ),
63
+ * } )
64
+ * ```
65
+ *
66
+ * @param sink The sink passed to the open as `indexSink`.
67
+ * @param options Rebuild pacing (see {@link PrefixTypeIndex}).
68
+ * @param options.growthFactor Record growth before a query rebuilds.
69
+ * @param options.minimumRecords Count below which pacing is skipped.
70
+ * @return {PrefixTypeIndex<EntityTypesIfc>} The index over that sink.
71
+ */
72
+ export function ifcPrefixTypeIndex(sink, options) {
73
+ return new PrefixTypeIndex(sink, new StepTypeIndexer(EntityTypesIfcCount), options);
74
+ }
75
+ /**
76
+ * Cooperative twin of {@link openStreamedIfcModel}: the index build
77
+ * yields to the event loop and can fill windows from an async
78
+ * {@link ReadableByteSource}. Pass a {@link StoreByteSource} wrapping
79
+ * `store` to parse a file that is already in OPFS without ever
80
+ * holding it as one `ArrayBuffer`.
81
+ *
82
+ * @param source Sync or async parse source.
83
+ * @param store The random-access store the model reads from afterwards.
84
+ * @param options See {@link StreamedIfcOpenOptions} plus `onProgress`.
85
+ * @return {Promise<StreamedIfcOpen>} The model + header, columns, diagnostics.
86
+ */
87
+ export async function openStreamedIfcModelAsync(source, store, options) {
88
+ if (store.byteLength !== source.byteLength) {
89
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match ` +
90
+ `source byteLength ${source.byteLength}`);
91
+ }
92
+ const { header, columns, result, stats } = await buildColumnarIndexStreamingAsync(source, IfcStepParser.Instance, options?.pool ?? DEFAULT_STREAM_POOL_BYTES, options?.onRecordIndexed, options?.onProgress, void 0, options?.indexSink);
93
+ if (result !== ParseResult.COMPLETE) {
94
+ return { model: void 0, result, header, columns, stats };
95
+ }
96
+ const provider = new WindowedStepBufferProvider(store, options?.chunkBytes, options?.maxResidentChunks);
97
+ return {
98
+ model: new IfcStepModel(void 0, columns, provider),
99
+ result,
100
+ header,
101
+ columns,
102
+ stats,
103
+ };
104
+ }
105
+ /**
106
+ * Open a windowed IFC model from a store alone — parse windows and
107
+ * post-parse reads share `store`. This is the M1b embedder entry for
108
+ * a file already sitting in OPFS.
109
+ *
110
+ * @param store The source of truth for the file bytes.
111
+ * @param options See {@link openStreamedIfcModelAsync}.
112
+ * @return {Promise<StreamedIfcOpen>} The model + header, columns, diagnostics.
113
+ */
114
+ export function openStreamedIfcModelFromStore(store, options) {
115
+ return openStreamedIfcModelAsync(new StoreByteSource(store), store, options);
116
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ifc_stream_open.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ifc_stream_open.test.d.ts","sourceRoot":"","sources":["../../../src/ifc/ifc_stream_open.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,230 @@
1
+ /* eslint-disable no-magic-numbers */
2
+ // Phase B3: the release-facing streamed open — fixed-memory columnar parse
3
+ // over a ByteSource, model over a windowed store, columns exposed for the
4
+ // revisit sidecar — behaves like a resident open for reads once ranges are
5
+ // resident.
6
+ import * as fs from "fs";
7
+ import { beforeAll, describe, expect, test } from "@jest/globals";
8
+ import ParsingBuffer from "../parsing/parsing_buffer.js";
9
+ import IfcStepParser from "./ifc_step_parser.js";
10
+ import { ifcPrefixTypeIndex, openStreamedIfcModel, openStreamedIfcModelFromStore, } from "./ifc_stream_open.js";
11
+ import { ColumnarIndexSink } from "../step/parsing/columnar_index.js";
12
+ import { BufferByteSource } from "../step/parsing/byte_source.js";
13
+ import { InMemoryStepByteStore } from "../step/step_buffer_provider.js";
14
+ import { ParseResult } from "../step/parsing/step_parser.js";
15
+ import { hashSource, serializeIndexSidecarFromColumns, deserializeIndexSidecarToColumns, sidecarMatchesSource, } from "../step/parsing/index_sidecar.js";
16
+ import { IfcRoot } from "./ifc4_gen/index.js";
17
+ let bytes;
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ let residentModel;
20
+ beforeAll(() => {
21
+ bytes = new Uint8Array(fs.readFileSync("data/index.ifc"));
22
+ const input = new ParsingBuffer(bytes);
23
+ IfcStepParser.Instance.parseHeader(input);
24
+ residentModel = IfcStepParser.Instance.parseDataToModel(input)[1];
25
+ });
26
+ describe("openStreamedIfcModel (Phase B3)", () => {
27
+ test("a caller-owned sink makes the type index queryable mid-parse", () => {
28
+ // The composed path a consumer of @bldrs-ai/conway/stream actually has:
29
+ // own the sink, hand it to the open, and read the index while the parse
30
+ // is still filling it. Without the sink seam the columns only exist once
31
+ // the open returns, which is too late for anything incremental.
32
+ const indexSink = new ColumnarIndexSink();
33
+ const types = ifcPrefixTypeIndex(indexSink, { growthFactor: 1, minimumRecords: 0 });
34
+ const midParse = [];
35
+ const open = openStreamedIfcModel(new BufferByteSource(bytes), new InMemoryStepByteStore(bytes), {
36
+ pool: 4 * 1024,
37
+ indexSink,
38
+ onRecordIndexed: (localID) => {
39
+ if (localID === 64 || localID === 128) {
40
+ midParse.push([...types.expressIDsOfTypes(IfcRoot)].length);
41
+ }
42
+ },
43
+ });
44
+ expect(open.result).toBe(ParseResult.COMPLETE);
45
+ expect(midParse).toHaveLength(2);
46
+ expect(midParse[0]).toBeLessThanOrEqual(midParse[1]);
47
+ const finalCount = [...types.expressIDsOfTypes(IfcRoot)].length;
48
+ expect(midParse[1]).toBeLessThanOrEqual(finalCount);
49
+ expect(finalCount).toBe([...residentModel.expressIDsOfTypes(IfcRoot)].length);
50
+ });
51
+ test("opens a model matching the resident parse, with header and columns", () => {
52
+ const open = openStreamedIfcModel(new BufferByteSource(bytes), new InMemoryStepByteStore(bytes), { pool: 4 * 1024 });
53
+ expect(open.result).toBe(ParseResult.COMPLETE);
54
+ expect(open.model).toBeDefined();
55
+ expect(open.header.headers.size).toBeGreaterThan(0);
56
+ expect(open.columns.firstInlineElement).toBeGreaterThan(0);
57
+ const streamedRoots = new Set(open.model.expressIDsOfTypes(IfcRoot));
58
+ const residentRoots = new Set(residentModel.expressIDsOfTypes(IfcRoot));
59
+ expect(streamedRoots).toEqual(residentRoots);
60
+ });
61
+ test("reads work after ensureResident (the windowed contract)", async () => {
62
+ const open = openStreamedIfcModel(new BufferByteSource(bytes), new InMemoryStepByteStore(bytes));
63
+ const model = open.model;
64
+ const expressID = [...model.expressIDsOfTypes(IfcRoot)][0];
65
+ await model.ensureResidentByExpressID(expressID);
66
+ const element = model.getElementByExpressID(expressID);
67
+ expect(element?.expressID).toBe(expressID);
68
+ });
69
+ test("record events fire live during the open", () => {
70
+ let events = 0;
71
+ openStreamedIfcModel(new BufferByteSource(bytes), new InMemoryStepByteStore(bytes), { onRecordIndexed: () => void ++events });
72
+ expect(events).toBe(openStreamedIfcModel(new BufferByteSource(bytes), new InMemoryStepByteStore(bytes)).columns.firstInlineElement);
73
+ });
74
+ test("the returned columns serialize to a trustable revisit sidecar", () => {
75
+ const open = openStreamedIfcModel(new BufferByteSource(bytes), new InMemoryStepByteStore(bytes));
76
+ const hash = hashSource(bytes);
77
+ const sidecar = serializeIndexSidecarFromColumns(open.columns, bytes.byteLength, hash);
78
+ const restored = deserializeIndexSidecarToColumns(sidecar);
79
+ expect(sidecarMatchesSource(
80
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
+ restored, bytes.byteLength, hash)).toBe(true);
82
+ expect(restored.columns.count).toBe(open.columns.firstInlineElement);
83
+ });
84
+ test("rejects a store whose length disagrees with the source", () => {
85
+ expect(() => openStreamedIfcModel(new BufferByteSource(bytes), new InMemoryStepByteStore(bytes.subarray(0, 100))))
86
+ .toThrow(/does not match/);
87
+ });
88
+ test("releaseSourceViews still lets a later read re-acquire", async () => {
89
+ const store = new InMemoryStepByteStore(bytes);
90
+ const fromStore = await openStreamedIfcModelFromStore(store, { pool: 4 * 1024 });
91
+ const model = fromStore.model;
92
+ const expressID = [...model.expressIDsOfTypes(IfcRoot)][0];
93
+ const localID = model.resolveExpressID(expressID);
94
+ await model.ensureResidentByLocalID(localID);
95
+ const first = model.getElementByExpressID(expressID);
96
+ expect(first).toBeDefined();
97
+ const args = first.extractLineArguments();
98
+ expect(args.length).toBeGreaterThan(0);
99
+ model.releaseSourceViews([localID]);
100
+ await model.ensureResidentByLocalID(localID);
101
+ const again = model.getElementByExpressID(expressID);
102
+ expect(again.extractLineArguments().length).toBe(args.length);
103
+ });
104
+ test("extractParseBuffer rematerialises after releaseSourceViews", async () => {
105
+ const store = new InMemoryStepByteStore(bytes);
106
+ const fromStore = await openStreamedIfcModelFromStore(store, { pool: 4 * 1024 });
107
+ const model = fromStore.model;
108
+ const expressID = [...model.expressIDsOfTypes(IfcRoot)][0];
109
+ const localID = model.resolveExpressID(expressID);
110
+ await model.ensureResidentByLocalID(localID);
111
+ const first = model.getElementByExpressID(expressID);
112
+ // Populate vtable + buffer the way a first extract does.
113
+ expect(first.extractLineArguments().length).toBeGreaterThan(0);
114
+ // A real heap rather than a stubbed HEAPU8.set. extractParseBuffer builds
115
+ // its destination through wasmHeapView now, which reconciles the pointer
116
+ // against the heap's actual buffer before writing (#485) - so the fake has
117
+ // to have one. It also makes the assertions stronger: the bytes are
118
+ // checked where they landed, not just counted on the way past.
119
+ const wasmHeap = new Uint8Array(4 * 1024);
120
+ const fakeModule = { HEAPU8: wasmHeap };
121
+ const copied = [];
122
+ const fakeResult = { resize: (n) => {
123
+ copied.push(n);
124
+ return 0;
125
+ } };
126
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
127
+ first.extractParseBuffer(0, 0, 0, fakeResult, fakeModule, true);
128
+ expect(copied[0]).toBeGreaterThan(0);
129
+ // Landed in the heap, at the pointer resize handed back.
130
+ const written = Array.from(wasmHeap.subarray(0, copied[0]));
131
+ expect(written.some((byte) => byte !== 0)).toBe(true);
132
+ model.releaseSourceViews([localID]);
133
+ await model.ensureResidentByLocalID(localID);
134
+ // Same entity object — vtable kept, buffer dropped. This is the
135
+ // PSB "Cannot read properties of undefined (reading 'subarray')" path.
136
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
137
+ first.extractParseBuffer(0, 0, 0, fakeResult, fakeModule, true);
138
+ expect(copied[1]).toBe(copied[0]);
139
+ });
140
+ test("ensureResidentClosureByLocalID visits every #ref hop", async () => {
141
+ const store = new InMemoryStepByteStore(bytes);
142
+ const fromStore = await openStreamedIfcModelFromStore(store, { pool: 4 * 1024 });
143
+ const model = fromStore.model;
144
+ const expressID = [...model.expressIDsOfTypes(IfcRoot)][0];
145
+ const localID = model.resolveExpressID(expressID);
146
+ await model.ensureResidentByLocalID(localID);
147
+ const refs = model.referencedExpressIDs(localID);
148
+ expect(refs.length).toBeGreaterThan(0);
149
+ const visited = await model.ensureResidentClosureByLocalID(localID);
150
+ expect(visited.has(localID)).toBe(true);
151
+ expect(model.typeIDOf(localID)).toBeDefined();
152
+ for (const refExpressID of refs) {
153
+ const refLocalID = model.resolveExpressID(refExpressID);
154
+ if (refLocalID !== void 0) {
155
+ expect(visited.has(refLocalID)).toBe(true);
156
+ }
157
+ }
158
+ });
159
+ test("ensureResidentClosureByLocalID skip-descend does not follow #refs", async () => {
160
+ const store = new InMemoryStepByteStore(bytes);
161
+ const fromStore = await openStreamedIfcModelFromStore(store, { pool: 4 * 1024 });
162
+ const model = fromStore.model;
163
+ const expressID = [...model.expressIDsOfTypes(IfcRoot)][0];
164
+ const localID = model.resolveExpressID(expressID);
165
+ await model.ensureResidentByLocalID(localID);
166
+ const refs = model.referencedExpressIDs(localID);
167
+ expect(refs.length).toBeGreaterThan(0);
168
+ const leafSpans = [];
169
+ const visited = await model.ensureResidentClosureByLocalID(localID, void 0, new Set(), (id) => id === localID, leafSpans);
170
+ expect(visited.has(localID)).toBe(true);
171
+ expect(visited.size).toBe(1);
172
+ expect(leafSpans.length).toBeGreaterThan(0);
173
+ expect(leafSpans[0].length).toBeGreaterThan(0);
174
+ });
175
+ test("spanLeaf spans children; !descend without spanLeaf still visits them", async () => {
176
+ const store = new InMemoryStepByteStore(bytes);
177
+ const fromStore = await openStreamedIfcModelFromStore(store, { pool: 4 * 1024 });
178
+ const model = fromStore.model;
179
+ const expressID = [...model.expressIDsOfTypes(IfcRoot)][0];
180
+ const localID = model.resolveExpressID(expressID);
181
+ await model.ensureResidentByLocalID(localID);
182
+ const refs = model.referencedExpressIDs(localID);
183
+ expect(refs.length).toBeGreaterThan(0);
184
+ const leafSpans = [];
185
+ const visited = await model.ensureResidentClosureByLocalID(localID, void 0, new Set(), (id) => id === localID, leafSpans, () => false);
186
+ expect(visited.has(localID)).toBe(true);
187
+ expect(visited.size).toBeGreaterThan(1);
188
+ expect(leafSpans.length).toBe(0);
189
+ });
190
+ test("spansOfExpressIDs covers each record without the holes between", async () => {
191
+ const store = new InMemoryStepByteStore(bytes);
192
+ const fromStore = await openStreamedIfcModelFromStore(store, { pool: 4 * 1024 });
193
+ const model = fromStore.model;
194
+ const expressIDs = [...model.expressIDsOfTypes(IfcRoot)];
195
+ expect(expressIDs.length).toBeGreaterThan(1);
196
+ const spans = model.spansOfExpressIDs(expressIDs);
197
+ expect(spans.length).toBeGreaterThan(0);
198
+ let covered = 0;
199
+ let hullMin = Infinity;
200
+ let hullMax = 0;
201
+ for (const span of spans) {
202
+ covered += span.length;
203
+ }
204
+ for (const refExpressID of expressIDs) {
205
+ const localID = model.resolveExpressID(refExpressID);
206
+ const address = model.recordAddress(localID);
207
+ const end = address + model.recordLength(localID);
208
+ if (address < hullMin) {
209
+ hullMin = address;
210
+ }
211
+ if (end > hullMax) {
212
+ hullMax = end;
213
+ }
214
+ const inside = spans.some((span) => address >= span.address && end <= span.address + span.length);
215
+ expect(inside).toBe(true);
216
+ }
217
+ // IfcRoot rows are scattered through index.ifc — the coalesced
218
+ // spans must not be the single hull from first to last.
219
+ expect(covered).toBeLessThan(hullMax - hullMin);
220
+ });
221
+ test("openStreamedIfcModelFromStore matches the sync open", async () => {
222
+ const store = new InMemoryStepByteStore(bytes);
223
+ const fromStore = await openStreamedIfcModelFromStore(store, { pool: 4 * 1024 });
224
+ const streamed = openStreamedIfcModel(new BufferByteSource(bytes), store, { pool: 4 * 1024 });
225
+ expect(fromStore.result).toBe(ParseResult.COMPLETE);
226
+ expect(fromStore.model.isSourceExternal).toBe(true);
227
+ expect([...fromStore.model.expressIDsOfTypes(IfcRoot)])
228
+ .toEqual([...streamed.model.expressIDsOfTypes(IfcRoot)]);
229
+ });
230
+ });