@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
@@ -944,7 +944,7 @@ var EntityTypesIfcCount = 909;
944
944
  var entity_types_ifc_gen_default = EntityTypesIfc;
945
945
 
946
946
  // compiled/src/version/version.js
947
- var versionString = "Conway v1.389.1221";
947
+ var versionString = "Conway v1.394.1504";
948
948
 
949
949
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
950
950
  var wasmType = "";
@@ -1288,10 +1288,12 @@ var Logger = class _Logger {
1288
1288
  *
1289
1289
  * @param level - log level
1290
1290
  * @param message - log message
1291
+ * @param expressID - record this entry is about, kept out of the message
1292
+ * text so repeats dedupe into one entry (see the class doc)
1291
1293
  */
1292
- static log(level, message) {
1294
+ static log(level, message, expressID) {
1293
1295
  const baseMessage = message.split(" expressID: ")[0];
1294
- const data = message.split(" expressID: ")[1];
1296
+ const data = expressID !== void 0 ? String(expressID) : message.split(" expressID: ")[1];
1295
1297
  const index = _Logger.findLogIndex(baseMessage, level);
1296
1298
  let logEntry;
1297
1299
  let firstOccurrence = false;
@@ -1313,7 +1315,7 @@ var Logger = class _Logger {
1313
1315
  _Logger.logs.push(logEntry);
1314
1316
  }
1315
1317
  if (firstOccurrence && _Logger.isLevelEnabled(LOG_LEVEL_BY_NAME[level])) {
1316
- _Logger.sink(level, baseMessage);
1318
+ _Logger.sink(level, data !== void 0 ? `${baseMessage} expressID: ${data}` : baseMessage);
1317
1319
  }
1318
1320
  _Logger.proxies.forEach((proxy) => proxy.log(logEntry));
1319
1321
  }
@@ -1418,16 +1420,18 @@ var Logger = class _Logger {
1418
1420
  /**
1419
1421
  *
1420
1422
  * @param message - log message
1423
+ * @param expressID - record this entry is about
1421
1424
  */
1422
- static warning(message) {
1423
- _Logger.log("warning", message);
1425
+ static warning(message, expressID) {
1426
+ _Logger.log("warning", message, expressID);
1424
1427
  }
1425
1428
  /**
1426
1429
  *
1427
1430
  * @param message - log message
1431
+ * @param expressID - record this entry is about
1428
1432
  */
1429
- static error(message) {
1430
- _Logger.log("error", message);
1433
+ static error(message, expressID) {
1434
+ _Logger.log("error", message, expressID);
1431
1435
  }
1432
1436
  /**
1433
1437
  *
@@ -1498,6 +1502,20 @@ var environment_default = Environment;
1498
1502
 
1499
1503
  // compiled/src/core/progress.js
1500
1504
  function yieldToEventLoop() {
1505
+ const scheduler = globalThis.scheduler;
1506
+ if (typeof scheduler?.yield === "function") {
1507
+ return scheduler.yield();
1508
+ }
1509
+ if (typeof MessageChannel === "function") {
1510
+ return new Promise((resolve) => {
1511
+ const channel = new MessageChannel();
1512
+ channel.port1.onmessage = () => {
1513
+ channel.port1.close();
1514
+ resolve();
1515
+ };
1516
+ channel.port2.postMessage(null);
1517
+ });
1518
+ }
1501
1519
  return new Promise((resolve) => {
1502
1520
  setTimeout(resolve, 0);
1503
1521
  });
@@ -2027,6 +2045,19 @@ function copyOutOfResizable(view) {
2027
2045
  function decodeUtf8(view) {
2028
2046
  return decoder.decode(decodeNeedsCopy(view.buffer) ? view.slice() : view);
2029
2047
  }
2048
+ var strictUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
2049
+ function decodeStepString(view) {
2050
+ const bytes = decodeNeedsCopy(view.buffer) ? view.slice() : view;
2051
+ try {
2052
+ return strictUtf8Decoder.decode(bytes);
2053
+ } catch {
2054
+ let result = "";
2055
+ for (let where = 0; where < bytes.length; ++where) {
2056
+ result += String.fromCharCode(bytes[where]);
2057
+ }
2058
+ return result;
2059
+ }
2060
+ }
2030
2061
  var shimInstalled = false;
2031
2062
  function installResizableTextDecoderShim() {
2032
2063
  if (shimInstalled || typeof TextDecoder === "undefined") {
@@ -2200,6 +2231,37 @@ var ParsingBuffer = class {
2200
2231
  this.buffer = buffer;
2201
2232
  this.end = endOffset;
2202
2233
  }
2234
+ /**
2235
+ * Streaming support: repoint this buffer at a fresh window over the same
2236
+ * logical stream while keeping `address` file-absolute.
2237
+ *
2238
+ * A moving-window parse holds only a slice of the source in memory at a
2239
+ * time. Between top-level records (where the rewind stack is empty) the
2240
+ * driver slides the window forward: it copies the unconsumed tail to the
2241
+ * front of a reused buffer, appends freshly-read bytes, and calls this to
2242
+ * repoint the parser. `addressBase` is the file offset that window index 0
2243
+ * now corresponds to; we store it as a negative initial offset so
2244
+ * `address` ( = cursor − initialOffset ) stays the file-absolute value the
2245
+ * non-streaming parse would have produced.
2246
+ *
2247
+ * Must only be called with the rewind stack empty (i.e. at a record
2248
+ * boundary) — the stack holds window-relative cursors that a slide would
2249
+ * invalidate. Throws otherwise.
2250
+ *
2251
+ * @param buffer The new window buffer.
2252
+ * @param cursorInWindow The cursor position within the new window.
2253
+ * @param endInWindow The count of valid bytes in the new window.
2254
+ * @param addressBase The file offset that window index 0 maps to.
2255
+ */
2256
+ rebaseWindow(buffer, cursorInWindow, endInWindow, addressBase) {
2257
+ if (this.rewindStack_.length !== 0) {
2258
+ throw Error("rebaseWindow called mid-transaction (rewind stack non-empty)");
2259
+ }
2260
+ this.buffer = buffer;
2261
+ this.cursor_ = cursorInWindow;
2262
+ this.initialOffset_ = -addressBase;
2263
+ this.end = endInWindow;
2264
+ }
2203
2265
  /**
2204
2266
  * Construct this with a buffer, initial offset into the buffer and an end offset.
2205
2267
  *
@@ -2683,14 +2745,14 @@ var StepStringParser = class extends ParsingDfa16Table {
2683
2745
  if (nextCursor < endCursor && input[nextCursor] === QUOTE) {
2684
2746
  result ??= "";
2685
2747
  if (cursor > reificationIndex) {
2686
- result += decodeUtf8(input.subarray(reificationIndex, cursor - 1));
2748
+ result += decodeStepString(input.subarray(reificationIndex, cursor - 1));
2687
2749
  }
2688
2750
  result += "'";
2689
2751
  cursor = nextCursor + 1;
2690
2752
  reificationIndex = cursor;
2691
2753
  } else {
2692
2754
  result ??= "";
2693
- result += decodeUtf8(input.subarray(reificationIndex, cursor));
2755
+ result += decodeStepString(input.subarray(reificationIndex, cursor));
2694
2756
  return result;
2695
2757
  }
2696
2758
  }
@@ -2716,7 +2778,7 @@ var StepStringParser = class extends ParsingDfa16Table {
2716
2778
  const nextChar2 = input[nextCursor2];
2717
2779
  if (nextChar2 !== BSLASH) {
2718
2780
  result ??= "";
2719
- result += decodeUtf8(input.subarray(reificationIndex, cursor));
2781
+ result += decodeStepString(input.subarray(reificationIndex, cursor));
2720
2782
  cursor = nextCursor2 + 1;
2721
2783
  break;
2722
2784
  }
@@ -2729,7 +2791,7 @@ var StepStringParser = class extends ParsingDfa16Table {
2729
2791
  return result;
2730
2792
  }
2731
2793
  result ??= "";
2732
- result += decodeUtf8(input.subarray(reificationIndex, cursor));
2794
+ result += decodeStepString(input.subarray(reificationIndex, cursor));
2733
2795
  codePage = nextChar3 - A2;
2734
2796
  cursor = nextCursor3 + 1;
2735
2797
  reificationIndex = cursor;
@@ -2743,7 +2805,7 @@ var StepStringParser = class extends ParsingDfa16Table {
2743
2805
  const nextChar2 = input[nextCursor2];
2744
2806
  if (nextChar2 !== BSLASH) {
2745
2807
  result ??= "";
2746
- result += decodeUtf8(input.subarray(reificationIndex, cursor));
2808
+ result += decodeStepString(input.subarray(reificationIndex, cursor));
2747
2809
  cursor = nextCursor2 + 1;
2748
2810
  break;
2749
2811
  }
@@ -2753,7 +2815,7 @@ var StepStringParser = class extends ParsingDfa16Table {
2753
2815
  }
2754
2816
  const nextChar3 = input[nextCursor3];
2755
2817
  result ??= "";
2756
- result += decodeUtf8(input.subarray(reificationIndex, cursor));
2818
+ result += decodeStepString(input.subarray(reificationIndex, cursor));
2757
2819
  if (nextChar3 < 127) {
2758
2820
  result += String.fromCharCode(nextChar3);
2759
2821
  } else if (nextChar >= 161 && nextChar <= 255) {
@@ -2772,7 +2834,7 @@ var StepStringParser = class extends ParsingDfa16Table {
2772
2834
  }
2773
2835
  const nextChar2 = input[nextCursor2];
2774
2836
  result ??= "";
2775
- result += decodeUtf8(input.subarray(reificationIndex, cursor));
2837
+ result += decodeStepString(input.subarray(reificationIndex, cursor));
2776
2838
  const hexParserTil0 = (count) => {
2777
2839
  if (nextCursor2 + 1 >= endCursor || input[nextCursor2 + 1] !== BSLASH) {
2778
2840
  return false;
@@ -3119,6 +3181,18 @@ function* stepExtractArray(buffer, cursor, endCursor) {
3119
3181
  throw new Error("Unterminated array");
3120
3182
  }
3121
3183
  }
3184
+ function stepEnterTypedValue(buffer, cursor, endCursor, typeName) {
3185
+ const identifierEnd = identifierParser.match(buffer, cursor, endCursor);
3186
+ if (identifierEnd === void 0 || identifierEnd - cursor !== typeName.length) {
3187
+ return cursor;
3188
+ }
3189
+ for (let where = 0; where < typeName.length; ++where) {
3190
+ if (buffer[cursor + where] !== typeName.charCodeAt(where)) {
3191
+ return cursor;
3192
+ }
3193
+ }
3194
+ return stepExtractInlineElemement(buffer, cursor, endCursor) ?? cursor;
3195
+ }
3122
3196
  function stepExtractInlineElemement(buffer, cursor, endCursor) {
3123
3197
  const identifier = identifierParser.match(buffer, cursor, endCursor);
3124
3198
  if (identifier === void 0) {
@@ -3449,9 +3523,87 @@ var StepParser = class extends StepHeaderParser {
3449
3523
  if (next.done === true) {
3450
3524
  return next.value;
3451
3525
  }
3526
+ if (typeof next.value === "number") {
3527
+ onProgress?.(next.value);
3528
+ }
3529
+ }
3530
+ }
3531
+ /**
3532
+ * Streaming driver over parseDataBlockIncremental: identical parse (same
3533
+ * generator body) but invokes `onRecordBoundary` at every top-level record
3534
+ * boundary so a caller feeding the parser from a moving window can slide
3535
+ * that window forward while the rewind stack is empty. See
3536
+ * streaming_index_builder.ts for the coordinator that owns the window.
3537
+ *
3538
+ * @param input The input parsing buffer, positioned at the data section.
3539
+ * @param onRecordBoundary Called at each top-level record boundary with the
3540
+ * buffer; the callback may rebase the buffer's window in place. Must be
3541
+ * synchronous on this driver — a returned Promise is a caller bug.
3542
+ * @param onRecordIndexed Called as each top-level record is indexed, with
3543
+ * its localID, expressID, typeID (0 for external-mapping records) and the
3544
+ * record's bytes as an un-materialised `(buffer, byteOffset, byteLength)`
3545
+ * window view — the seam for incremental semantic consumers (type index,
3546
+ * roots registry, names skeleton). See {@link RecordEventHandler} for the
3547
+ * window-lifetime rule. Must be synchronous and cheap; expensive work
3548
+ * belongs on a demand queue, not the parse path.
3549
+ * @param onProgress Optional byte-cursor progress callback.
3550
+ * @return {BlockParseResult} The parsing result, including the index and result enum.
3551
+ */
3552
+ parseDataBlockStreamed(input, onRecordBoundary, onRecordIndexed, onProgress, sink) {
3553
+ const parser211 = this.parseDataBlockIncremental(input, onRecordBoundary, onRecordIndexed, sink);
3554
+ while (true) {
3555
+ const next = parser211.next();
3556
+ if (next.done === true) {
3557
+ return next.value;
3558
+ }
3559
+ if (typeof next.value !== "number") {
3560
+ throw new Error("parseDataBlockStreamed: async window slide requires parseDataBlockStreamedAsync");
3561
+ }
3452
3562
  onProgress?.(next.value);
3453
3563
  }
3454
3564
  }
3565
+ /**
3566
+ * Cooperative variant of parseDataBlockStreamed: identical parse and
3567
+ * window-slide behaviour (same generator body, same boundary callback),
3568
+ * but periodically awaits a macrotask so the event loop can run —
3569
+ * browsers repaint progress UI during a large streamed parse instead of
3570
+ * flagging the tab as stalled. Issue #301 §2 for the streamed path.
3571
+ *
3572
+ * @param input The input parsing buffer, positioned at the data section.
3573
+ * @param onRecordBoundary Called at each top-level record boundary with the
3574
+ * buffer; the callback may rebase the buffer's window in place. May return
3575
+ * a Promise when the slide itself is I/O (an async ByteSource); this
3576
+ * driver awaits it before the next record is lexed.
3577
+ * @param onRecordIndexed Called as each top-level record is indexed — see
3578
+ * parseDataBlockStreamed.
3579
+ * @param onProgress Optional byte-cursor progress callback.
3580
+ * @param sink Optional index sink (columnar builds).
3581
+ * @param yieldIntervalMs Minimum ms between event-loop yields.
3582
+ * @return {Promise<BlockParseResult>} The parsing result, including the
3583
+ * index and result enum.
3584
+ */
3585
+ async parseDataBlockStreamedAsync(input, onRecordBoundary, onRecordIndexed, onProgress, sink, yieldIntervalMs = DEFAULT_PARSE_YIELD_INTERVAL_MS) {
3586
+ const parser211 = this.parseDataBlockIncremental(input, onRecordBoundary, onRecordIndexed, sink);
3587
+ let lastYield = Date.now();
3588
+ while (true) {
3589
+ const next = parser211.next();
3590
+ if (next.done === true) {
3591
+ return next.value;
3592
+ }
3593
+ if (typeof next.value !== "number") {
3594
+ await next.value;
3595
+ continue;
3596
+ }
3597
+ const progressed = onProgress?.(next.value);
3598
+ if (progressed !== void 0 && typeof progressed.then === "function") {
3599
+ await progressed;
3600
+ }
3601
+ if (Date.now() - lastYield >= yieldIntervalMs) {
3602
+ await yieldToEventLoop();
3603
+ lastYield = Date.now();
3604
+ }
3605
+ }
3606
+ }
3455
3607
  /**
3456
3608
  * Cooperative variant of parseDataBlock: identical parse (same generator
3457
3609
  * body), but periodically awaits a macrotask so the event loop can run —
@@ -3472,7 +3624,9 @@ var StepParser = class extends StepHeaderParser {
3472
3624
  if (next.done === true) {
3473
3625
  return next.value;
3474
3626
  }
3475
- onProgress?.(next.value);
3627
+ if (typeof next.value === "number") {
3628
+ onProgress?.(next.value);
3629
+ }
3476
3630
  if (Date.now() - lastYield >= yieldIntervalMs) {
3477
3631
  await yieldToEventLoop();
3478
3632
  lastYield = Date.now();
@@ -3489,8 +3643,14 @@ var StepParser = class extends StepHeaderParser {
3489
3643
  * @yields {number} The current byte cursor within the input buffer.
3490
3644
  * @return {BlockParseResult} The parsing result, including the index and result enum.
3491
3645
  */
3492
- *parseDataBlockIncremental(input) {
3646
+ *parseDataBlockIncremental(input, onRecordBoundary, onRecordIndexed, sink) {
3493
3647
  const indexResult = { elements: [] };
3648
+ let topLevelCount = 0;
3649
+ const pushEntry = sink !== void 0 ? (entry) => {
3650
+ sink.pushTopLevel(entry);
3651
+ } : (entry) => {
3652
+ indexResult.elements.push(entry);
3653
+ };
3494
3654
  const match = input.match;
3495
3655
  const comment = () => match(commentParser2);
3496
3656
  const whitespace = () => {
@@ -3536,7 +3696,7 @@ var StepParser = class extends StepHeaderParser {
3536
3696
  return syntaxError();
3537
3697
  }
3538
3698
  whitespace();
3539
- const startElement = input.cursor;
3699
+ const startElement = input.address;
3540
3700
  let stackDepth = 1;
3541
3701
  const savedInlineElements = inlineElements;
3542
3702
  inlineElements = void 0;
@@ -3630,6 +3790,10 @@ var StepParser = class extends StepHeaderParser {
3630
3790
  if ((++parsedElementCount & PARSE_PROGRESS_ELEMENT_MASK) === 0) {
3631
3791
  yield input.cursor;
3632
3792
  }
3793
+ const slide = onRecordBoundary?.(input);
3794
+ if (slide !== void 0 && typeof slide.then === "function") {
3795
+ yield slide;
3796
+ }
3633
3797
  if (!charws(HASH2)) {
3634
3798
  if (tokenws(END_SECTION)) {
3635
3799
  return parseResult2(ParseResult.COMPLETE);
@@ -3652,7 +3816,7 @@ var StepParser = class extends StepHeaderParser {
3652
3816
  }
3653
3817
  whitespace();
3654
3818
  inlineElements = void 0;
3655
- const startElement2 = input.cursor;
3819
+ const startElement2 = input.address;
3656
3820
  while (!charws(CLOSE_PAREN2)) {
3657
3821
  input.begin();
3658
3822
  const elementResult = parseInlineElement(expressID);
@@ -3665,7 +3829,7 @@ var StepParser = class extends StepHeaderParser {
3665
3829
  if (!charws(SEMICOLON)) {
3666
3830
  return syntaxError();
3667
3831
  }
3668
- indexResult.elements.push({
3832
+ pushEntry({
3669
3833
  address: startElement2,
3670
3834
  length: input.address - startElement2,
3671
3835
  typeID: 0,
@@ -3674,6 +3838,11 @@ var StepParser = class extends StepHeaderParser {
3674
3838
  inlineEntities: inlineElements,
3675
3839
  multiMapping: multiElements
3676
3840
  });
3841
+ {
3842
+ const recordLen = input.address - startElement2;
3843
+ onRecordIndexed?.(topLevelCount, expressID, 0, input.buffer, input.cursor - recordLen, recordLen);
3844
+ }
3845
+ ++topLevelCount;
3677
3846
  multiElements = void 0;
3678
3847
  continue;
3679
3848
  }
@@ -3683,7 +3852,7 @@ var StepParser = class extends StepHeaderParser {
3683
3852
  return syntaxError();
3684
3853
  }
3685
3854
  whitespace();
3686
- const startElement = input.cursor;
3855
+ const startElement = input.address;
3687
3856
  let stackDepth = 1;
3688
3857
  inlineElements = void 0;
3689
3858
  while (stackDepth > 0) {
@@ -3710,9 +3879,6 @@ var StepParser = class extends StepHeaderParser {
3710
3879
  input.begin();
3711
3880
  const elementResult = parseInlineElement();
3712
3881
  if (elementResult !== void 0) {
3713
- for (const element of elementResult[0].elements) {
3714
- element.expressID = expressID;
3715
- }
3716
3882
  input.rollback();
3717
3883
  if (tokenws(INF)) {
3718
3884
  break;
@@ -3756,13 +3922,18 @@ var StepParser = class extends StepHeaderParser {
3756
3922
  if (!charws(SEMICOLON)) {
3757
3923
  return syntaxError();
3758
3924
  }
3759
- indexResult.elements.push({
3925
+ pushEntry({
3760
3926
  address: startElement,
3761
3927
  length: input.address - startElement,
3762
3928
  typeID: foundItem,
3763
3929
  expressID,
3764
3930
  inlineEntities: inlineElements
3765
3931
  });
3932
+ {
3933
+ const recordLen = input.address - startElement;
3934
+ onRecordIndexed?.(topLevelCount, expressID, foundItem, input.buffer, input.cursor - recordLen, recordLen);
3935
+ }
3936
+ ++topLevelCount;
3766
3937
  }
3767
3938
  return parseResult2(ParseResult.INCOMPLETE);
3768
3939
  }
@@ -4255,6 +4426,70 @@ var encodedDataEntityTypesIfc = new TextEncoder().encode("IFCSECTIONEDSPINEIFCST
4255
4426
  var EntityTypesIfcSearch = new MinimalPerfectHash(gMapEntityTypesIfc, prefixSumAddressEntityTypesIfc, slotMapEntityTypesIfc, encodedDataEntityTypesIfc);
4256
4427
  var entity_types_search_gen_default = EntityTypesIfcSearch;
4257
4428
 
4429
+ // compiled/src/step/parsing/express_ref_scan.js
4430
+ var HASH3 = 35;
4431
+ var QUOTE4 = 39;
4432
+ var DQUOTE = 34;
4433
+ var ZERO5 = 48;
4434
+ var NINE2 = 57;
4435
+ var SLASH3 = 47;
4436
+ var STAR2 = 42;
4437
+ function scanExpressRefs(bytes, from = 0, length = bytes.length - from) {
4438
+ const refs = [];
4439
+ const seen = /* @__PURE__ */ new Set();
4440
+ const end = Math.min(from + length, bytes.length);
4441
+ let cursor = from;
4442
+ while (cursor < end) {
4443
+ const byte = bytes[cursor];
4444
+ if (byte === QUOTE4) {
4445
+ cursor = skipQuoted_(bytes, cursor + 1, end, QUOTE4, true);
4446
+ continue;
4447
+ }
4448
+ if (byte === DQUOTE) {
4449
+ cursor = skipQuoted_(bytes, cursor + 1, end, DQUOTE, false);
4450
+ continue;
4451
+ }
4452
+ if (byte === SLASH3 && cursor + 1 < end && bytes[cursor + 1] === STAR2) {
4453
+ cursor += 2;
4454
+ while (cursor + 1 < end && !(bytes[cursor] === STAR2 && bytes[cursor + 1] === SLASH3)) {
4455
+ ++cursor;
4456
+ }
4457
+ cursor += 2;
4458
+ continue;
4459
+ }
4460
+ if (byte === HASH3) {
4461
+ let value = 0;
4462
+ let digit = cursor + 1;
4463
+ while (digit < end && bytes[digit] >= ZERO5 && bytes[digit] <= NINE2) {
4464
+ value = value * 10 + (bytes[digit] - ZERO5);
4465
+ ++digit;
4466
+ }
4467
+ if (digit > cursor + 1 && value !== 0 && !seen.has(value)) {
4468
+ seen.add(value);
4469
+ refs.push(value);
4470
+ }
4471
+ cursor = digit;
4472
+ continue;
4473
+ }
4474
+ ++cursor;
4475
+ }
4476
+ return refs;
4477
+ }
4478
+ function skipQuoted_(bytes, from, end, quote, doubledEscape) {
4479
+ let cursor = from;
4480
+ while (cursor < end) {
4481
+ if (bytes[cursor] === quote) {
4482
+ if (doubledEscape && cursor + 1 < end && bytes[cursor + 1] === quote) {
4483
+ cursor += 2;
4484
+ continue;
4485
+ }
4486
+ return cursor + 1;
4487
+ }
4488
+ ++cursor;
4489
+ }
4490
+ return end;
4491
+ }
4492
+
4258
4493
  // compiled/src/step/step_buffer_provider.js
4259
4494
  var DEFAULT_CHUNK_BYTES = 4 * 1024 * 1024;
4260
4495
  var DEFAULT_MAX_RESIDENT_CHUNKS = 16;
@@ -4435,7 +4670,7 @@ var WindowedStepBufferProvider = class {
4435
4670
  const firstChunk = Math.floor(address / chunkBytes);
4436
4671
  const lastChunk = Math.floor((address + Math.max(length, 1) - 1) / chunkBytes);
4437
4672
  for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; ++chunkIndex) {
4438
- this.ensurePins_.set(chunkIndex, (this.ensurePins_.get(chunkIndex) ?? 0) + 1);
4673
+ this.addPin_(chunkIndex, 1);
4439
4674
  }
4440
4675
  try {
4441
4676
  const loads = [];
@@ -4478,15 +4713,63 @@ var WindowedStepBufferProvider = class {
4478
4713
  }
4479
4714
  } finally {
4480
4715
  for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; ++chunkIndex) {
4481
- const pins = this.ensurePins_.get(chunkIndex) ?? 0;
4482
- if (pins <= 1) {
4483
- this.ensurePins_.delete(chunkIndex);
4484
- } else {
4485
- this.ensurePins_.set(chunkIndex, pins - 1);
4486
- }
4716
+ this.addPin_(chunkIndex, -1);
4487
4717
  }
4488
4718
  }
4489
4719
  }
4720
+ /**
4721
+ * Hold a range against LRU eviction until {@link unpinRange}.
4722
+ *
4723
+ * @param address Absolute start of the range.
4724
+ * @param length Length of the range.
4725
+ */
4726
+ pinRange(address, length) {
4727
+ for (const chunkIndex of this.chunkSpan_(address, length)) {
4728
+ this.addPin_(chunkIndex, 1);
4729
+ }
4730
+ }
4731
+ /**
4732
+ * Drop one {@link pinRange} hold.
4733
+ *
4734
+ * @param address Absolute start of the range.
4735
+ * @param length Length of the range.
4736
+ */
4737
+ unpinRange(address, length) {
4738
+ for (const chunkIndex of this.chunkSpan_(address, length)) {
4739
+ this.addPin_(chunkIndex, -1);
4740
+ }
4741
+ }
4742
+ /**
4743
+ * Chunk indices covering `[address, address + length)`.
4744
+ *
4745
+ * @param address Absolute start.
4746
+ * @param length Length in bytes.
4747
+ * @return {number[]} Inclusive chunk indices.
4748
+ */
4749
+ chunkSpan_(address, length) {
4750
+ const chunkBytes = this.chunkBytes_;
4751
+ const firstChunk = Math.floor(address / chunkBytes);
4752
+ const lastChunk = Math.floor((address + Math.max(length, 1) - 1) / chunkBytes);
4753
+ const span = [];
4754
+ for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; ++chunkIndex) {
4755
+ span.push(chunkIndex);
4756
+ }
4757
+ return span;
4758
+ }
4759
+ /**
4760
+ * Adjust a chunk's pin count, deleting the entry at zero.
4761
+ *
4762
+ * @param chunkIndex The chunk.
4763
+ * @param delta +1 pin or -1 unpin.
4764
+ */
4765
+ addPin_(chunkIndex, delta) {
4766
+ const pins = (this.ensurePins_.get(chunkIndex) ?? 0) + delta;
4767
+ if (pins <= 0) {
4768
+ this.ensurePins_.delete(chunkIndex);
4769
+ } else {
4770
+ this.ensurePins_.set(chunkIndex, pins);
4771
+ }
4772
+ }
4490
4773
  };
4491
4774
 
4492
4775
  // compiled/src/step/parsing/step_vtable_builder.js
@@ -4552,6 +4835,101 @@ var StepVtableBuilder = class {
4552
4835
  }
4553
4836
  };
4554
4837
 
4838
+ // compiled/src/step/parsing/uint32_sink.js
4839
+ var OPEN_PAREN3 = parsing_constants_default.OPEN_PAREN;
4840
+ var CLOSE_PAREN3 = parsing_constants_default.CLOSE_PAREN;
4841
+ var COMMA3 = parsing_constants_default.COMMA;
4842
+ var ZERO6 = parsing_constants_default.ZERO;
4843
+ var WHITESPACE4 = parsing_constants_default.WHITE_SPACE_SET;
4844
+ function extractIntegerArrayAt(buffer, cursor, endCursor, sink) {
4845
+ const marked = sink.length;
4846
+ const fast = extractUnsignedIntegerListAt(buffer, cursor, endCursor, sink);
4847
+ if (fast !== void 0) {
4848
+ return fast;
4849
+ }
4850
+ sink.truncate(marked);
4851
+ if (stepExtractOptional(buffer, cursor, endCursor) === null) {
4852
+ return 0;
4853
+ }
4854
+ let count = 0;
4855
+ let signedCursor0 = stepExtractArrayBegin(buffer, cursor, endCursor);
4856
+ let readCursor = Math.abs(signedCursor0);
4857
+ while (signedCursor0 >= 0) {
4858
+ const value = stepExtractNumber(buffer, readCursor, endCursor);
4859
+ if (value === void 0) {
4860
+ throw new Error("Value in STEP was incorrectly typed");
4861
+ }
4862
+ readCursor = skipValue(buffer, readCursor, endCursor);
4863
+ sink.push(value);
4864
+ ++count;
4865
+ signedCursor0 = stepExtractArrayToken(buffer, readCursor, endCursor);
4866
+ readCursor = Math.abs(signedCursor0);
4867
+ }
4868
+ return count;
4869
+ }
4870
+ function extractUnsignedIntegerListAt(buffer, cursor, endCursor, sink) {
4871
+ const marked = sink.length;
4872
+ while (cursor < endCursor && WHITESPACE4.has(buffer[cursor])) {
4873
+ ++cursor;
4874
+ }
4875
+ if (cursor >= endCursor) {
4876
+ return void 0;
4877
+ }
4878
+ if (buffer[cursor] === parsing_constants_default.DOLLAR) {
4879
+ return 0;
4880
+ }
4881
+ if (buffer[cursor] !== OPEN_PAREN3) {
4882
+ return void 0;
4883
+ }
4884
+ ++cursor;
4885
+ let count = 0;
4886
+ while (cursor < endCursor) {
4887
+ while (cursor < endCursor && WHITESPACE4.has(buffer[cursor])) {
4888
+ ++cursor;
4889
+ }
4890
+ if (cursor >= endCursor) {
4891
+ sink.truncate(marked);
4892
+ return void 0;
4893
+ }
4894
+ if (buffer[cursor] === CLOSE_PAREN3) {
4895
+ return count;
4896
+ }
4897
+ if (count > 0) {
4898
+ if (buffer[cursor] !== COMMA3) {
4899
+ sink.truncate(marked);
4900
+ return void 0;
4901
+ }
4902
+ ++cursor;
4903
+ while (cursor < endCursor && WHITESPACE4.has(buffer[cursor])) {
4904
+ ++cursor;
4905
+ }
4906
+ if (cursor >= endCursor) {
4907
+ sink.truncate(marked);
4908
+ return void 0;
4909
+ }
4910
+ }
4911
+ const digit = buffer[cursor] - ZERO6;
4912
+ if (digit < 0 || digit > 9) {
4913
+ sink.truncate(marked);
4914
+ return void 0;
4915
+ }
4916
+ let value = digit;
4917
+ ++cursor;
4918
+ while (cursor < endCursor) {
4919
+ const next = buffer[cursor] - ZERO6;
4920
+ if (next < 0 || next > 9) {
4921
+ break;
4922
+ }
4923
+ value = value * 10 + next;
4924
+ ++cursor;
4925
+ }
4926
+ sink.push(value);
4927
+ ++count;
4928
+ }
4929
+ sink.truncate(marked);
4930
+ return void 0;
4931
+ }
4932
+
4555
4933
  // compiled/src/indexing/index_set_constants.js
4556
4934
  var IndexSetConstants = class {
4557
4935
  };
@@ -4913,23 +5291,54 @@ var InterpolationSearchTable32 = class {
4913
5291
  };
4914
5292
 
4915
5293
  // compiled/src/step/step_model_base.js
4916
- var StepModelBase = class {
5294
+ var StepModelBase = class _StepModelBase {
4917
5295
  /**
4918
5296
  * Construct this step model with its matching schema, a buffer to read from and an element index.
4919
5297
  *
4920
5298
  * @param schema The Step schema this is based on.
4921
- * @param buffer_ The buffer to read this from.
5299
+ * @param buffer_ The buffer to read this from. Pass `undefined` together
5300
+ * with `provider` to build a model whose source is windowed from
5301
+ * construction (e.g. a streaming open — see buildModelStreaming); the
5302
+ * synchronous read paths (geometry extraction) then require the relevant
5303
+ * ranges to be resident, exactly as after `spillSourceToExternalStore`.
4922
5304
  * @param elementIndex The element index for this, parsed or deserialized - note this takes
4923
5305
  * ownership of this array in the sense it will modify values/unfold inline elements etc.
5306
+ * @param provider Optional pre-built buffer provider. When omitted, a
5307
+ * resident provider over `buffer_` is used (the classic path).
4924
5308
  */
4925
- constructor(schema, buffer_, elementIndex) {
5309
+ constructor(schema, buffer_, elementIndex, provider) {
4926
5310
  this.schema = schema;
4927
5311
  this.buffer_ = buffer_;
4928
5312
  this.vtableBuilder_ = new StepVtableBuilder();
4929
5313
  this.descriptorCache_ = [];
4930
5314
  this.elementMemoization = true;
4931
5315
  this.nullOnErrors = true;
4932
- this.bufferProvider_ = new ResidentStepBufferProvider(buffer_);
5316
+ this.bufferProvider_ = provider ?? new ResidentStepBufferProvider(buffer_);
5317
+ if (!Array.isArray(elementIndex)) {
5318
+ const columns = elementIndex;
5319
+ const firstInline = columns.firstInlineElement;
5320
+ const inlineCount = columns.count - firstInline;
5321
+ const inlineElementTable2 = new Uint32Array(inlineCount << 1);
5322
+ for (let where2 = 0; where2 < inlineCount; ++where2) {
5323
+ inlineElementTable2[where2 << 1] = firstInline + where2;
5324
+ inlineElementTable2[(where2 << 1) + 1] = columns.address[firstInline + where2];
5325
+ }
5326
+ this.inlineAddressMap_ = new InterpolationSearchTable32(inlineElementTable2, true);
5327
+ const expressIdTable2 = new Uint32Array(firstInline << 1);
5328
+ for (let where2 = 0; where2 < firstInline; ++where2) {
5329
+ expressIdTable2[where2 << 1] = where2;
5330
+ expressIdTable2[(where2 << 1) + 1] = columns.expressID[where2];
5331
+ }
5332
+ this.expressIDMap_ = new InterpolationSearchTable32(expressIdTable2, columns.expressIdsSorted);
5333
+ this.address_ = columns.address;
5334
+ this.length_ = columns.length;
5335
+ this.typeID_ = columns.typeID;
5336
+ this.expressID_ = columns.expressID;
5337
+ this.count_ = columns.count;
5338
+ this.firstInlineElement_ = firstInline;
5339
+ this.complexEntries_ = columns.complexEntries;
5340
+ return;
5341
+ }
4933
5342
  const localElementIndex = elementIndex;
4934
5343
  let where = 0;
4935
5344
  const firstInlineElement = localElementIndex.length;
@@ -5072,11 +5481,94 @@ var StepModelBase = class {
5072
5481
  }
5073
5482
  }
5074
5483
  /**
5075
- * Populate a raw vtable entry for a particular element, extra
5484
+ * Resolve an express ID to a local ID, using `hintLocalID + 1` when
5485
+ * the next record is the one we want. Tessellated Faces lists are
5486
+ * sequential (PSB: every faceset), so this turns 9.1M interpolation
5487
+ * searches into one per faceset.
5076
5488
  *
5077
- * @param element The raw elment to populate the vtable entry for.
5078
- * @return {boolean} Did the vtable entry populate correctly?
5489
+ * @param expressID The referenced record.
5490
+ * @param hintLocalID Local ID of the previous resolve, if any.
5491
+ * @return {number | undefined} The local ID, or undefined if unknown.
5079
5492
  */
5493
+ resolveExpressID(expressID, hintLocalID) {
5494
+ if (hintLocalID !== void 0) {
5495
+ const next = hintLocalID + 1;
5496
+ if (next < this.firstInlineElement_ && this.expressID_[next] === expressID) {
5497
+ return next;
5498
+ }
5499
+ }
5500
+ return this.expressIDMap_.get(expressID);
5501
+ }
5502
+ /**
5503
+ * Append a local record's unsigned-integer list field into `sink`
5504
+ * without an express-ID lookup. The reference-level twin of
5505
+ * `StepEntityBase.extractIntegerArrayInto`, for hot loops that walk
5506
+ * millions of small records (tessellated facesets) where constructing
5507
+ * an entity per record dominates. It deliberately handles only the
5508
+ * simple case and reports failure otherwise, so callers keep a
5509
+ * correct fallback rather than this growing subtle special cases:
5510
+ * the record must be single-class (no multi-mapping) and exactly
5511
+ * `expectedTypeID`.
5512
+ *
5513
+ * Field 0 is the data-block start the parser stored in `address_`
5514
+ * (after `TYPE(`). Reading it from the columns skips the descriptor
5515
+ * and vtable `entry()` would retain — on a 9 M-face model those are
5516
+ * the objects the faceset path is trying not to build. Non-zero
5517
+ * offsets still go through a vtable, because only field 0 has that
5518
+ * address identity.
5519
+ *
5520
+ * @param localID The record's local ID.
5521
+ * @param offset The field's vtable offset.
5522
+ * @param expectedTypeID The type the record must be.
5523
+ * @param sink Receives the appended values.
5524
+ * @return {number | undefined} Count appended, or undefined when the
5525
+ * fast path does not apply.
5526
+ */
5527
+ extractIntegerArrayByLocalIDInto(localID, offset, expectedTypeID, sink) {
5528
+ if (localID >= this.count_) {
5529
+ return void 0;
5530
+ }
5531
+ if (this.complexEntries_?.has(localID) || this.typeID_[localID] !== expectedTypeID) {
5532
+ return void 0;
5533
+ }
5534
+ if (offset === 0) {
5535
+ const address = this.address_[localID];
5536
+ const acquisition = this.bufferProvider_.acquire(address, this.length_[localID]);
5537
+ const viewAddress = address - acquisition.offset;
5538
+ return extractIntegerArrayAt(acquisition.buffer, viewAddress, acquisition.buffer.length, sink);
5539
+ }
5540
+ const element = this.entry(localID);
5541
+ if (element.vtableIndex === void 0 && !this.populateVtableEntryRaw(element)) {
5542
+ return void 0;
5543
+ }
5544
+ if (element.buffer === void 0) {
5545
+ this.populateBufferEntry(localID);
5546
+ }
5547
+ const vtable = element.vtable;
5548
+ const buffer = element.buffer;
5549
+ if (vtable === void 0 || buffer === void 0 || offset >= (element.vtableCount ?? 0)) {
5550
+ return void 0;
5551
+ }
5552
+ return extractIntegerArrayAt(buffer, vtable[element.vtableIndex + offset], buffer.length, sink);
5553
+ }
5554
+ /**
5555
+ * Append a referenced record's unsigned-integer list field into `sink`
5556
+ * without materialising the referenced entity.
5557
+ *
5558
+ * @param expressID The referenced record's express ID.
5559
+ * @param offset The field's vtable offset within the record.
5560
+ * @param expectedTypeID The type the record must be.
5561
+ * @param sink Receives the appended values.
5562
+ * @return {number | undefined} Count appended, or undefined when the
5563
+ * fast path does not apply.
5564
+ */
5565
+ extractIntegerArrayByExpressIDInto(expressID, offset, expectedTypeID, sink) {
5566
+ const localID = this.expressIDMap_.get(expressID);
5567
+ if (localID === void 0) {
5568
+ return void 0;
5569
+ }
5570
+ return this.extractIntegerArrayByLocalIDInto(localID, offset, expectedTypeID, sink);
5571
+ }
5080
5572
  populateVtableEntryRaw(element) {
5081
5573
  if (element.vtableIndex !== void 0 || element.typeID === 0) {
5082
5574
  return true;
@@ -5121,6 +5613,11 @@ var StepModelBase = class {
5121
5613
  }
5122
5614
  const element = this.entry(localID);
5123
5615
  element.buffer = this.bufferProvider_.acquire(element.address, element.length).buffer;
5616
+ if (element.multiMapping !== void 0) {
5617
+ for (const mapped of element.multiMapping) {
5618
+ mapped.buffer = this.bufferProvider_.acquire(mapped.address, mapped.length).buffer;
5619
+ }
5620
+ }
5124
5621
  }
5125
5622
  /**
5126
5623
  * Get the size in bytes of the backing buffer for this.
@@ -5148,6 +5645,74 @@ var StepModelBase = class {
5148
5645
  get residentSourceBytes() {
5149
5646
  return this.bufferProvider_.residentBytes;
5150
5647
  }
5648
+ /**
5649
+ * Column type of a record, or `undefined` if the id is unknown / untyped.
5650
+ *
5651
+ * @param localID The record.
5652
+ * @return {number | undefined} The schema type id.
5653
+ */
5654
+ typeIDOf(localID) {
5655
+ if (localID >= this.count_) {
5656
+ return;
5657
+ }
5658
+ const typeID = this.typeID_[localID];
5659
+ return typeID < 0 ? void 0 : typeID;
5660
+ }
5661
+ /**
5662
+ * Absolute source address of a record.
5663
+ *
5664
+ * @param localID The record.
5665
+ * @return {number | undefined} The address.
5666
+ */
5667
+ recordAddress(localID) {
5668
+ return localID < this.count_ ? this.address_[localID] : void 0;
5669
+ }
5670
+ /**
5671
+ * Source length of a record.
5672
+ *
5673
+ * @param localID The record.
5674
+ * @return {number | undefined} The length.
5675
+ */
5676
+ recordLength(localID) {
5677
+ return localID < this.count_ ? this.length_[localID] : void 0;
5678
+ }
5679
+ /**
5680
+ * Pin an arbitrary source span (e.g. a faceset's packed Faces[] run).
5681
+ *
5682
+ * @param address Absolute start.
5683
+ * @param length Length in bytes.
5684
+ */
5685
+ pinAddressRange(address, length) {
5686
+ if (!this.isSourceExternal) {
5687
+ return;
5688
+ }
5689
+ this.bufferProvider_.pinRange?.(address, length);
5690
+ }
5691
+ /**
5692
+ * Drop one {@link pinAddressRange} hold.
5693
+ *
5694
+ * @param address Absolute start.
5695
+ * @param length Length in bytes.
5696
+ */
5697
+ unpinAddressRange(address, length) {
5698
+ if (!this.isSourceExternal) {
5699
+ return;
5700
+ }
5701
+ this.bufferProvider_.unpinRange?.(address, length);
5702
+ }
5703
+ /**
5704
+ * Page an arbitrary source span.
5705
+ *
5706
+ * @param address Absolute start.
5707
+ * @param length Length in bytes.
5708
+ * @return {Promise<void>} Resolves when resident.
5709
+ */
5710
+ async ensureResidentRange(address, length) {
5711
+ if (!this.isSourceExternal) {
5712
+ return;
5713
+ }
5714
+ await this.bufferProvider_.ensureResident(address, length);
5715
+ }
5151
5716
  /**
5152
5717
  * Release the resident source buffer and serve subsequent record
5153
5718
  * reads from fixed-size windows paged in from an external store.
@@ -5222,6 +5787,320 @@ var StepModelBase = class {
5222
5787
  }
5223
5788
  await this.ensureResidentByLocalID(localID);
5224
5789
  }
5790
+ /**
5791
+ * Page in the byte ranges a record *and every `#ref` reachable from
5792
+ * its text* will need, so a following synchronous extract of that
5793
+ * subgraph succeeds on a windowed source. Inverse relationships
5794
+ * (not written in the record) are not discovered — callers that
5795
+ * need them (rel-voids, styled items) pass their local IDs as
5796
+ * `extraLocalIDs`.
5797
+ *
5798
+ * No-op while the source is fully resident.
5799
+ *
5800
+ * @param localID Seed record.
5801
+ * @param extraLocalIDs Additional seeds (voids, styles, materials).
5802
+ * @param seen Optional set to extend (also skips already-pinned IDs).
5803
+ * @param descend If set, records for which this returns false are
5804
+ * still visited (pinned, in `seen`) but their `#refs` are not
5805
+ * followed — e.g. an `IfcPolygonalFaceSet` whose Faces[] payload
5806
+ * is paged as one span afterwards.
5807
+ * @param leafSpans Optional out-array of coalesced pin ranges for
5808
+ * {@link spanLeaf} children — caller must {@link unpinAddressRange}
5809
+ * each.
5810
+ * @param spanLeaf If set, matching children are *not* visited
5811
+ * (absent from `seen`); their bytes are one pin span. Packed
5812
+ * extract reads `IfcIndexedPolygonalFace.CoordIndex` as integers —
5813
+ * following those faces pinned ~78k records per PSB product. If
5814
+ * omitted, `!descend` children use this span path (test helper).
5815
+ * @param claimed Optional out-set of the IDs *this call* claimed and
5816
+ * awaited residency for — a strict subset of `seen`. When `seen` is
5817
+ * shared across concurrent walks (a batch of products sharing mapped
5818
+ * geometry), an ID another walk claimed is skipped here and is NOT
5819
+ * resident yet from this call's point of view: that walk's pin holds
5820
+ * the chunk once it lands, but its read is still in flight. Anything
5821
+ * that must synchronously read a record's bytes after this returns
5822
+ * has to iterate `claimed`, never `seen` (conway#526).
5823
+ * @return {Promise<Set<number>>} The local IDs that were visited.
5824
+ */
5825
+ async ensureResidentClosureByLocalID(localID, extraLocalIDs, seen = /* @__PURE__ */ new Set(), descend, leafSpans, spanLeaf, claimed) {
5826
+ if (!this.isSourceExternal) {
5827
+ return seen;
5828
+ }
5829
+ const frontier = [];
5830
+ const enqueue = (id) => {
5831
+ if (id < this.count_ && !seen.has(id)) {
5832
+ frontier.push(id);
5833
+ }
5834
+ };
5835
+ enqueue(localID);
5836
+ if (extraLocalIDs !== void 0) {
5837
+ for (const extra of extraLocalIDs) {
5838
+ enqueue(extra);
5839
+ }
5840
+ }
5841
+ while (frontier.length > 0) {
5842
+ const wave = [];
5843
+ for (const id of frontier) {
5844
+ if (seen.has(id) || id >= this.count_) {
5845
+ continue;
5846
+ }
5847
+ seen.add(id);
5848
+ this.pinByLocalID(id);
5849
+ wave.push(id);
5850
+ claimed?.add(id);
5851
+ }
5852
+ frontier.length = 0;
5853
+ if (wave.length === 0) {
5854
+ break;
5855
+ }
5856
+ await Promise.all(wave.map((id) => this.ensureResidentByLocalID(id)));
5857
+ const waveSpans = [];
5858
+ for (const id of wave) {
5859
+ if (descend !== void 0 && !descend(id)) {
5860
+ continue;
5861
+ }
5862
+ const skipped = [];
5863
+ for (const expressID of this.scanRecordRefs_(id)) {
5864
+ const referenced = this.expressIDMap_.get(expressID);
5865
+ if (referenced === void 0 || seen.has(referenced)) {
5866
+ continue;
5867
+ }
5868
+ const leaf = spanLeaf !== void 0 ? spanLeaf(referenced) : descend !== void 0 && !descend(referenced);
5869
+ if (leaf) {
5870
+ skipped.push(referenced);
5871
+ continue;
5872
+ }
5873
+ frontier.push(referenced);
5874
+ }
5875
+ if (skipped.length > 0) {
5876
+ for (const span of this.spansOf_(skipped)) {
5877
+ this.pinAddressRange(span.address, span.length);
5878
+ waveSpans.push(span);
5879
+ leafSpans?.push(span);
5880
+ }
5881
+ }
5882
+ }
5883
+ if (waveSpans.length > 0) {
5884
+ await Promise.all(waveSpans.map((span) => this.ensureResidentRange(span.address, span.length)));
5885
+ }
5886
+ }
5887
+ return seen;
5888
+ }
5889
+ /**
5890
+ * Hold a record's source range against windowed LRU eviction until
5891
+ * {@link unpinByLocalID}. No-op while the source is fully resident.
5892
+ *
5893
+ * @param localID The record to pin.
5894
+ */
5895
+ pinByLocalID(localID) {
5896
+ if (!this.isSourceExternal || localID >= this.count_) {
5897
+ return;
5898
+ }
5899
+ this.bufferProvider_.pinRange?.(this.address_[localID], this.length_[localID]);
5900
+ }
5901
+ /**
5902
+ * Drop one {@link pinByLocalID} hold.
5903
+ *
5904
+ * @param localID The record to unpin.
5905
+ */
5906
+ unpinByLocalID(localID) {
5907
+ if (!this.isSourceExternal || localID >= this.count_) {
5908
+ return;
5909
+ }
5910
+ this.bufferProvider_.unpinRange?.(this.address_[localID], this.length_[localID]);
5911
+ }
5912
+ /**
5913
+ * Drop captured source-window views on `localIDs` so the LRU can
5914
+ * evict those chunks. Vtables stay — `acquire` of the same
5915
+ * `(address, length)` is at a stable base. The next
5916
+ * `ensureResident` + field read rematerialises the view.
5917
+ *
5918
+ * @param localIDs Records whose `buffer` views to drop.
5919
+ */
5920
+ releaseSourceViews(localIDs) {
5921
+ if (!this.isSourceExternal) {
5922
+ return;
5923
+ }
5924
+ for (const localID of localIDs) {
5925
+ if (localID >= this.count_) {
5926
+ continue;
5927
+ }
5928
+ const item = this.complexEntries_?.get(localID) ?? this.descriptorCache_[localID];
5929
+ if (item === void 0) {
5930
+ continue;
5931
+ }
5932
+ item.buffer = void 0;
5933
+ if (item.multiMapping !== void 0) {
5934
+ for (const mapped of item.multiMapping) {
5935
+ mapped.buffer = void 0;
5936
+ }
5937
+ }
5938
+ }
5939
+ releaseScratchParsingBuffer();
5940
+ }
5941
+ /**
5942
+ * Unpin every local ID in `localIDs` (best-effort; missing IDs are
5943
+ * ignored). Use after {@link ensureResidentClosureByLocalID}, which
5944
+ * pins as it walks.
5945
+ *
5946
+ * @param localIDs The records to unpin.
5947
+ */
5948
+ unpinLocalIDs(localIDs) {
5949
+ for (const localID of localIDs) {
5950
+ this.unpinByLocalID(localID);
5951
+ }
5952
+ }
5953
+ /**
5954
+ * Express-ID twin of {@link ensureResidentClosureByLocalID}. Unknown
5955
+ * IDs resolve to an empty visit set.
5956
+ *
5957
+ * @param expressID Seed record.
5958
+ * @param extraLocalIDs Additional seeds (local IDs).
5959
+ * @return {Promise<Set<number>>} The local IDs that were visited.
5960
+ */
5961
+ async ensureResidentClosureByExpressID(expressID, extraLocalIDs, seen) {
5962
+ if (!this.isSourceExternal) {
5963
+ return seen ?? /* @__PURE__ */ new Set();
5964
+ }
5965
+ const localID = this.expressIDMap_.get(expressID);
5966
+ if (localID === void 0) {
5967
+ return seen ?? /* @__PURE__ */ new Set();
5968
+ }
5969
+ return this.ensureResidentClosureByLocalID(localID, extraLocalIDs, seen);
5970
+ }
5971
+ /**
5972
+ * Source spans covering the records referenced by `expressIDs` from
5973
+ * `fromIndex` onward. A packed Faces[] run is consecutive in parse
5974
+ * order — two express-ID lookups then cover the whole range. Sparse
5975
+ * sets are coalesced into tight runs so intervening file is not
5976
+ * pinned.
5977
+ *
5978
+ * @param expressIDs Referenced express IDs (e.g. a faceset's #refs).
5979
+ * @param fromIndex First index to include (skip Coordinates at [0]).
5980
+ * @return {{address: number, length: number}[]} The spans.
5981
+ */
5982
+ spansOfExpressIDs(expressIDs, fromIndex = 0) {
5983
+ let minExpressID = Infinity;
5984
+ let maxExpressID = 0;
5985
+ let count = 0;
5986
+ for (let i = fromIndex; i < expressIDs.length; ++i) {
5987
+ const expressID = expressIDs[i];
5988
+ if (expressID < minExpressID) {
5989
+ minExpressID = expressID;
5990
+ }
5991
+ if (expressID > maxExpressID) {
5992
+ maxExpressID = expressID;
5993
+ }
5994
+ ++count;
5995
+ }
5996
+ if (count === 0 || !Number.isFinite(minExpressID)) {
5997
+ return [];
5998
+ }
5999
+ const minLocal = this.expressIDMap_.get(minExpressID);
6000
+ const maxLocal = this.expressIDMap_.get(maxExpressID);
6001
+ if (minLocal === void 0 || maxLocal === void 0) {
6002
+ return [];
6003
+ }
6004
+ const lo = Math.min(minLocal, maxLocal);
6005
+ const hi = Math.max(minLocal, maxLocal);
6006
+ if (hi - lo + 1 === count) {
6007
+ const address = this.address_[lo];
6008
+ const end = this.address_[hi] + this.length_[hi];
6009
+ if (end <= address) {
6010
+ return [];
6011
+ }
6012
+ return [{ address, length: end - address }];
6013
+ }
6014
+ const locals = [];
6015
+ for (let i = fromIndex; i < expressIDs.length; ++i) {
6016
+ const localID = this.expressIDMap_.get(expressIDs[i]);
6017
+ if (localID !== void 0) {
6018
+ locals.push(localID);
6019
+ }
6020
+ }
6021
+ return this.spansOf_(locals);
6022
+ }
6023
+ /**
6024
+ * Coalesce `localIDs` into tight source runs. Records more than
6025
+ * {@link LEAF_SPAN_COALESCE_GAP_} apart stay separate so a sparse
6026
+ * Faces[] list does not pin the file between them.
6027
+ *
6028
+ * @param localIDs The records.
6029
+ * @return {{address: number, length: number}[]} The spans.
6030
+ */
6031
+ spansOf_(localIDs) {
6032
+ const items = [];
6033
+ for (const id of localIDs) {
6034
+ if (id >= this.count_) {
6035
+ continue;
6036
+ }
6037
+ items.push({
6038
+ address: this.address_[id],
6039
+ length: this.length_[id]
6040
+ });
6041
+ }
6042
+ items.sort((a2, b) => a2.address - b.address);
6043
+ const spans = [];
6044
+ let run;
6045
+ for (const item of items) {
6046
+ if (run === void 0) {
6047
+ run = { address: item.address, length: item.length };
6048
+ continue;
6049
+ }
6050
+ const runEnd = run.address + run.length;
6051
+ if (item.address <= runEnd + _StepModelBase.LEAF_SPAN_COALESCE_GAP_) {
6052
+ const end = Math.max(runEnd, item.address + item.length);
6053
+ run.length = end - run.address;
6054
+ continue;
6055
+ }
6056
+ spans.push(run);
6057
+ run = { address: item.address, length: item.length };
6058
+ }
6059
+ if (run !== void 0) {
6060
+ spans.push(run);
6061
+ }
6062
+ return spans;
6063
+ }
6064
+ /**
6065
+ * Express IDs referenced by a resident record (`#<id>` tokens in its
6066
+ * text, including multi-mapped class records). The record itself
6067
+ * must already be resident.
6068
+ *
6069
+ * @param localID The record to scan.
6070
+ * @return {number[]} Distinct referenced express IDs.
6071
+ */
6072
+ referencedExpressIDs(localID) {
6073
+ return this.scanRecordRefs_(localID);
6074
+ }
6075
+ /**
6076
+ * Scan a resident record's bytes for `#<expressID>` references.
6077
+ *
6078
+ * @param localID The record to scan.
6079
+ * @return {number[]} Distinct referenced express IDs.
6080
+ */
6081
+ scanRecordRefs_(localID) {
6082
+ const address = this.address_[localID];
6083
+ const length = this.length_[localID];
6084
+ const acquisition = this.bufferProvider_.acquire(address, length);
6085
+ const viewStart = address - acquisition.offset;
6086
+ const refs = scanExpressRefs(acquisition.buffer, viewStart, length);
6087
+ const complex = this.complexEntries_?.get(localID);
6088
+ if (complex?.multiMapping === void 0) {
6089
+ return refs;
6090
+ }
6091
+ const seen = new Set(refs);
6092
+ for (const mapped of complex.multiMapping) {
6093
+ const mappedAcquisition = this.bufferProvider_.acquire(mapped.address, mapped.length);
6094
+ const mappedStart = mapped.address - mappedAcquisition.offset;
6095
+ for (const expressID of scanExpressRefs(mappedAcquisition.buffer, mappedStart, mapped.length)) {
6096
+ if (!seen.has(expressID)) {
6097
+ seen.add(expressID);
6098
+ refs.push(expressID);
6099
+ }
6100
+ }
6101
+ }
6102
+ return refs;
6103
+ }
5225
6104
  /**
5226
6105
  * Get the number of elements/entities in this model.
5227
6106
  *
@@ -5606,6 +6485,8 @@ var StepModelBase = class {
5606
6485
  return this.geometry?.getByLocalID(node.localID);
5607
6486
  }
5608
6487
  };
6488
+ StepModelBase.LEAF_SPAN_COALESCE_GAP_ = 1024;
6489
+ var step_model_base_default = StepModelBase;
5609
6490
 
5610
6491
  // compiled/src/core/entity_field_description.js
5611
6492
  var FieldDescriptionKind;
@@ -10193,6 +11074,67 @@ function IfcWorkScheduleTypeEnumDeserializeStep(input, cursor, endCursor) {
10193
11074
  return parser208.extract(IfcWorkScheduleTypeEnumSearch, input, cursor, endCursor);
10194
11075
  }
10195
11076
 
11077
+ // compiled/src/core/wasm_heap.js
11078
+ function describeHeap(wasmModule, arrayPtr, numBytes) {
11079
+ const heap = wasmModule.HEAPU8;
11080
+ const buffer = currentHeapBuffer(wasmModule);
11081
+ const shared = typeof SharedArrayBuffer !== "undefined" && buffer instanceof SharedArrayBuffer;
11082
+ const kind = buffer === void 0 ? "none" : shared ? "SharedArrayBuffer" : "ArrayBuffer";
11083
+ const extensible = shared ? buffer?.growable : buffer?.resizable;
11084
+ return `ptr ${arrayPtr} + ${numBytes} bytes, heap view length ${heap?.length}, buffer ${kind} byteLength ${buffer?.byteLength}, extensible ${extensible}`;
11085
+ }
11086
+ function currentHeapBuffer(wasmModule) {
11087
+ const memory = wasmModule.wasmMemory;
11088
+ return memory !== void 0 ? memory.buffer : wasmModule.HEAPU8?.buffer;
11089
+ }
11090
+ function refreshHeapViews(wasmModule) {
11091
+ if (typeof wasmModule.updateMemoryViews === "function") {
11092
+ wasmModule.updateMemoryViews();
11093
+ return;
11094
+ }
11095
+ if (wasmModule.wasmMemory !== void 0) {
11096
+ return;
11097
+ }
11098
+ const StringVector = wasmModule.stringVector;
11099
+ if (StringVector === void 0) {
11100
+ return;
11101
+ }
11102
+ let scratch;
11103
+ releaseQuietly(() => {
11104
+ const created2 = new StringVector();
11105
+ scratch = created2;
11106
+ created2.push_back("");
11107
+ });
11108
+ const created = scratch;
11109
+ if (created !== void 0) {
11110
+ releaseQuietly(() => created.delete());
11111
+ }
11112
+ }
11113
+ function reconcileHeapBuffer(wasmModule, address, numBytes) {
11114
+ const buffer = currentHeapBuffer(wasmModule);
11115
+ if (buffer !== void 0 && address + numBytes <= buffer.byteLength) {
11116
+ return buffer;
11117
+ }
11118
+ refreshHeapViews(wasmModule);
11119
+ const refreshed = currentHeapBuffer(wasmModule);
11120
+ if (refreshed !== void 0 && address + numBytes <= refreshed.byteLength) {
11121
+ return refreshed;
11122
+ }
11123
+ throw new Error("wasm heap allocation lies outside the heap, and refreshing the module views did not reconcile it. " + describeHeap(wasmModule, address, numBytes));
11124
+ }
11125
+ function wasmHeapView(wasmModule, arrayType, pointer, elementCount) {
11126
+ const address = pointer >>> 0;
11127
+ const numBytes = elementCount * arrayType.BYTES_PER_ELEMENT;
11128
+ return new arrayType(reconcileHeapBuffer(wasmModule, address, numBytes), address, elementCount);
11129
+ }
11130
+ function releaseQuietly(release) {
11131
+ try {
11132
+ release();
11133
+ } catch (error) {
11134
+ logger_default.debug(`wasm resource release failed during teardown: ${error instanceof Error ? error.message : error}`);
11135
+ }
11136
+ }
11137
+
10196
11138
  // compiled/src/step/step_entity_base.js
10197
11139
  var IfcTokenType;
10198
11140
  (function(IfcTokenType2) {
@@ -10349,6 +11291,27 @@ var StepEntityBase = class {
10349
11291
  }
10350
11292
  return value;
10351
11293
  }
11294
+ /**
11295
+ * Extract a number at the particular vtable offset (i.e. the position
11296
+ * in the matching step object).
11297
+ *
11298
+ * Used by other extraction methods with wrappers to perform
11299
+ * semantically correct extraction.
11300
+ *
11301
+ * Unlike the other extractors this has a single signature rather than an
11302
+ * optional/non-optional overload pair, because LOGICAL is three-valued:
11303
+ * `.U.` is a legitimate value that reads as null, so a non-optional LOGICAL
11304
+ * is null-valued too and `optional` only decides whether a *missing* value
11305
+ * throws. The old `optional: false` overload promised a bare `boolean` and
11306
+ * was a lie for exactly the `.U.` case this extractor exists to handle.
11307
+ *
11308
+ * @param offset The offset in the vtable to extract from
11309
+ * @param baseOffset The base offset in the vtable to extract from
11310
+ * @param depth The depth of the vtable to extract from
11311
+ * @param optional Is this an optional field?
11312
+ * @return {boolean | null} The extracted logical, or null for `.U.` and for
11313
+ * an absent optional.
11314
+ */
10352
11315
  extractLogical(offset, baseOffset, depth, optional) {
10353
11316
  const [cursor, endCursor, buffer] = this.getOffsetAndEndCursor(offset, baseOffset, depth);
10354
11317
  const value = stepExtractLogical(buffer, cursor, endCursor);
@@ -10378,6 +11341,38 @@ var StepEntityBase = class {
10378
11341
  }
10379
11342
  return value;
10380
11343
  }
11344
+ /**
11345
+ * Resolve a single reference field to its local ID without
11346
+ * constructing the target entity. Prep maps that only store
11347
+ * `Item.localID` (IfcStyledItem → faceset) must not hydrate the
11348
+ * target: on a windowed source that would pin the faceset record
11349
+ * (often megabytes) for every styled item at once.
11350
+ *
11351
+ * @param offset The offset in the vtable to extract from.
11352
+ * @param baseOffset The base offset of the class in the vtable.
11353
+ * @param depth The depth in the inheritance hierarchy.
11354
+ * @param optional Is this an optional field?
11355
+ * @return {number | null} The referenced local ID, or null if the
11356
+ * field is unset/optional-null.
11357
+ */
11358
+ extractReferenceLocalID(offset, baseOffset, depth, optional) {
11359
+ const [cursor, endCursor, buffer] = this.getOffsetAndEndCursor(offset, baseOffset, depth);
11360
+ const expressID = stepExtractReference(buffer, cursor, endCursor);
11361
+ if (expressID !== void 0) {
11362
+ return this.model.resolveExpressID(expressID) ?? null;
11363
+ }
11364
+ const inline = this.model.getInlineElementByAddress(extractInlineElementAddress(buffer, cursor, endCursor));
11365
+ if (inline !== void 0) {
11366
+ return inline.localID;
11367
+ }
11368
+ if (!optional) {
11369
+ throw new Error("Value in STEP was incorrectly typed");
11370
+ }
11371
+ if (!this.model.nullOnErrors && stepExtractOptional(buffer, cursor, endCursor) !== null) {
11372
+ throw new Error("Value in STEP was incorrectly typed");
11373
+ }
11374
+ return null;
11375
+ }
10381
11376
  /**
10382
11377
  *
10383
11378
  * @param buffer
@@ -10583,6 +11578,7 @@ var StepEntityBase = class {
10583
11578
  */
10584
11579
  extractParseBuffer(offset, baseOffset, depth, result, module2, optional) {
10585
11580
  offset -= this.multiReference_ !== void 0 ? baseOffset : 0;
11581
+ this.guaranteeBuffer();
10586
11582
  const internalReference = this.guaranteeVTable(depth);
10587
11583
  if (offset >= internalReference.vtableCount) {
10588
11584
  throw new Error("Couldn't read field due to too few fields in record");
@@ -10595,10 +11591,72 @@ var StepEntityBase = class {
10595
11591
  if (optional && stepExtractOptional(buffer, cursor, endCursor) === null) {
10596
11592
  return false;
10597
11593
  }
10598
- const dataPtr = result.resize(endCursor - cursor);
10599
- module2.HEAPU8.set(buffer.subarray(cursor, endCursor), dataPtr);
11594
+ const length = endCursor - cursor;
11595
+ const dataPtr = result.resize(length);
11596
+ wasmHeapView(module2, Uint8Array, dataPtr, length).set(buffer.subarray(cursor, endCursor));
11597
+ return true;
11598
+ }
11599
+ /**
11600
+ * Append an unsigned-integer list field straight from the STEP buffer
11601
+ * into `sink`, without materialising an intermediate `Array< number >`.
11602
+ *
11603
+ * Semantically identical to the generated array getters (same
11604
+ * optional handling, same element extraction, same "incorrectly
11605
+ * typed" error), but it neither allocates nor caches a per-record
11606
+ * array — the caller owns one reusable sink for the whole batch. On
11607
+ * tessellated models this removes millions of short-lived arrays and
11608
+ * the retained heap that goes with them; see Uint32Sink.
11609
+ *
11610
+ * @param offset The offset in the vtable to extract from.
11611
+ * @param baseOffset The base offset of the class in the vtable.
11612
+ * @param depth The depth in the inheritance hierarchy.
11613
+ * @param sink Receives the appended values.
11614
+ * @return {number} How many values were appended (0 when the field is
11615
+ * unset/optional-null).
11616
+ */
11617
+ /**
11618
+ * Walk a reference-list field, handing each element's express ID to
11619
+ * `onReference` without resolving it to an entity.
11620
+ *
11621
+ * Lets hot loops decide per element how to read the referenced record
11622
+ * (see StepModelBase.extractIntegerArrayByExpressIDInto) instead of
11623
+ * paying for an entity per element the way the generated list getters
11624
+ * do. Inline (non-reference) elements yield `undefined`, and
11625
+ * `onReference` returning false aborts the walk — together those let
11626
+ * a caller bail out to the generated getter for anything it is not
11627
+ * prepared to handle.
11628
+ *
11629
+ * @param offset The offset in the vtable to extract from.
11630
+ * @param baseOffset The base offset of the class in the vtable.
11631
+ * @param depth The depth in the inheritance hierarchy.
11632
+ * @param onReference Receives each element's express ID, or undefined
11633
+ * for an inline element; return false to abort.
11634
+ * @return {boolean} False if the walk was aborted, true otherwise.
11635
+ */
11636
+ forEachReferenceInField(offset, baseOffset, depth, onReference) {
11637
+ let cursor = this.getOffsetCursor(offset, baseOffset, depth);
11638
+ const buffer = this.buffer;
11639
+ const endCursor = buffer.length;
11640
+ if (stepExtractOptional(buffer, cursor, endCursor) === null) {
11641
+ return true;
11642
+ }
11643
+ let signedCursor0 = stepExtractArrayBegin(buffer, cursor, endCursor);
11644
+ cursor = Math.abs(signedCursor0);
11645
+ while (signedCursor0 >= 0) {
11646
+ if (!onReference(stepExtractReference(buffer, cursor, endCursor))) {
11647
+ return false;
11648
+ }
11649
+ cursor = skipValue(buffer, cursor, endCursor);
11650
+ signedCursor0 = stepExtractArrayToken(buffer, cursor, endCursor);
11651
+ cursor = Math.abs(signedCursor0);
11652
+ }
10600
11653
  return true;
10601
11654
  }
11655
+ extractIntegerArrayInto(offset, baseOffset, depth, sink) {
11656
+ const cursor = this.getOffsetCursor(offset, baseOffset, depth);
11657
+ const buffer = this.buffer;
11658
+ return extractIntegerArrayAt(buffer, cursor, buffer.length, sink);
11659
+ }
10602
11660
  /**
10603
11661
  * Extract a number at the particular vtable offset (i.e. the position
10604
11662
  * in the matching step object).
@@ -10634,6 +11692,7 @@ var StepEntityBase = class {
10634
11692
  * @return {Uint8Array} The buffer for this.
10635
11693
  */
10636
11694
  get buffer() {
11695
+ this.guaranteeBuffer();
10637
11696
  return this.internalReference_.buffer;
10638
11697
  }
10639
11698
  /**
@@ -10724,6 +11783,9 @@ var StepEntityBase = class {
10724
11783
  throw new Error("Entity does not have matching table entry to read from model");
10725
11784
  }
10726
11785
  }
11786
+ if (classReference.buffer === void 0) {
11787
+ this.model.populateBufferEntry(this.localID);
11788
+ }
10727
11789
  this.internalReference_.buffer = classReference.buffer;
10728
11790
  return classReference;
10729
11791
  }
@@ -10734,6 +11796,9 @@ var StepEntityBase = class {
10734
11796
  throw new Error("Entity does not have matching table entry to read from model");
10735
11797
  }
10736
11798
  }
11799
+ if (internalReference.buffer === void 0) {
11800
+ this.guaranteeBuffer();
11801
+ }
10737
11802
  return internalReference;
10738
11803
  }
10739
11804
  /**
@@ -12560,7 +13625,7 @@ var IfcPresentationStyleAssignment = class extends StepEntityBase {
12560
13625
  let signedCursor0 = stepExtractArrayBegin(buffer, cursor, endCursor);
12561
13626
  cursor = Math.abs(signedCursor0);
12562
13627
  while (signedCursor0 >= 0) {
12563
- const value1Untyped = this.extractBufferReference(buffer, cursor, endCursor) ?? IfcNullStyleDeserializeStep(buffer, cursor, endCursor);
13628
+ const value1Untyped = this.extractBufferReference(buffer, cursor, endCursor) ?? IfcNullStyleDeserializeStep(buffer, stepEnterTypedValue(buffer, cursor, endCursor, "IFCNULLSTYLE"), endCursor);
12564
13629
  if (!(value1Untyped instanceof IfcCurveStyle) && !(value1Untyped instanceof IfcFillAreaStyle) && !(value1Untyped instanceof IfcSurfaceStyle) && !(value1Untyped instanceof IfcTextStyle) && value1Untyped !== IfcNullStyle.NULL) {
12565
13630
  throw new Error("Value in select must be populated");
12566
13631
  }
@@ -14388,7 +15453,7 @@ var IfcLogical = class extends StepEntityBase {
14388
15453
  }
14389
15454
  get Value() {
14390
15455
  if (this.Value_ === void 0) {
14391
- this.Value_ = this.extractBoolean(0, 0, 0, false);
15456
+ this.Value_ = this.extractLogical(0, 0, 0, false);
14392
15457
  }
14393
15458
  return this.Value_;
14394
15459
  }
@@ -25510,7 +26575,7 @@ var IfcRelInterferesElements = class extends IfcRelConnects {
25510
26575
  }
25511
26576
  get ImpliedOrder() {
25512
26577
  if (this.ImpliedOrder_ === void 0) {
25513
- this.ImpliedOrder_ = this.extractBoolean(8, 4, 3, false);
26578
+ this.ImpliedOrder_ = this.extractLogical(8, 4, 3, false);
25514
26579
  }
25515
26580
  return this.ImpliedOrder_;
25516
26581
  }
@@ -63778,7 +64843,7 @@ var descriptions = [
63778
64843
  },
63779
64844
  ImpliedOrder: {
63780
64845
  kind: f.BOOLEAN,
63781
- optional: false,
64846
+ optional: true,
63782
64847
  derived: false,
63783
64848
  offset: 8
63784
64849
  }
@@ -68750,7 +69815,7 @@ var descriptions = [
68750
69815
  fields: {
68751
69816
  Value: {
68752
69817
  kind: f.BOOLEAN,
68753
- optional: false,
69818
+ optional: true,
68754
69819
  derived: false,
68755
69820
  offset: 0
68756
69821
  }
@@ -70047,6 +71112,68 @@ var StepTypeIndexer = class {
70047
71112
  constructor(typeCount) {
70048
71113
  this.elementCounter_ = new Int32Array(typeCount << 1);
70049
71114
  }
71115
+ /**
71116
+ * Create a type index from either index form — the parsed object array or
71117
+ * the columnar index (M7).
71118
+ *
71119
+ * @param index The element index, object or columnar.
71120
+ * @return {MultiIndexSet} The created multi-set index.
71121
+ */
71122
+ createFor(index) {
71123
+ return Array.isArray(index) ? this.create(index) : this.createFromColumns(index);
71124
+ }
71125
+ /**
71126
+ * Create a type index straight from the columnar index — the same
71127
+ * membership `create` produces from the unfolded object array: every row's
71128
+ * concrete type (top-level + inline; −1 rows skipped) plus the
71129
+ * multi-mapping subtypes of retained complex entries at their parent's
71130
+ * dense index.
71131
+ *
71132
+ * @param columns The columnar index.
71133
+ * @return {MultiIndexSet} The created multi-set index.
71134
+ */
71135
+ createFromColumns(columns) {
71136
+ for (let where = 0, end = this.elementCounter_.length; where < end; where += 2) {
71137
+ initCountCompactedElements32State(this.elementCounter_, where);
71138
+ }
71139
+ const elementCounter = this.elementCounter_;
71140
+ const prefixSum = new Uint32Array((this.elementCounter_.length >>> 1) + 1);
71141
+ const typeIDs = columns.typeID;
71142
+ const count = columns.count;
71143
+ const walkRows = (addOne) => {
71144
+ const complexIterator = columns.complexEntries?.entries();
71145
+ let nextComplex = complexIterator?.next();
71146
+ for (let denseIndex = 0; denseIndex < count; ++denseIndex) {
71147
+ const typeID = typeIDs[denseIndex];
71148
+ if (typeID >= 0) {
71149
+ addOne(denseIndex, typeID);
71150
+ }
71151
+ if (nextComplex !== void 0 && !nextComplex.done && nextComplex.value[0] === denseIndex) {
71152
+ for (const subElement of nextComplex.value[1].multiMapping ?? []) {
71153
+ const subTypeID = subElement.typeID;
71154
+ if (subTypeID !== void 0) {
71155
+ addOne(denseIndex, subTypeID);
71156
+ }
71157
+ }
71158
+ nextComplex = complexIterator.next();
71159
+ }
71160
+ }
71161
+ };
71162
+ walkRows((denseIndex, typeID) => {
71163
+ prefixSum[typeID + 1] = addCompactedElementCount32State(denseIndex, elementCounter, typeID << 1);
71164
+ });
71165
+ for (let prefixSumIndex = 2, prefixSumEnd = prefixSum.length; prefixSumIndex < prefixSumEnd; ++prefixSumIndex) {
71166
+ prefixSum[prefixSumIndex] += prefixSum[prefixSumIndex - 1];
71167
+ }
71168
+ for (let where = 0, end = this.elementCounter_.length; where < end; where += 2) {
71169
+ initCountCompactedElements32State(this.elementCounter_, where);
71170
+ }
71171
+ const indexOutput = new Uint32Array(prefixSum[prefixSum.length - 1] << 1);
71172
+ walkRows((denseIndex, typeID) => {
71173
+ addCompactedElement32State(denseIndex, elementCounter, indexOutput, typeID << 1, prefixSum[typeID] << 1);
71174
+ });
71175
+ return new MultiIndexSet(prefixSum, indexOutput);
71176
+ }
70050
71177
  /**
70051
71178
  * Create a type index from a set of parsed STEP elements.
70052
71179
  *
@@ -70214,9 +71341,24 @@ var IfcModelGeometry = class {
70214
71341
  /**
70215
71342
  * Add a mesh to the geometry cache.
70216
71343
  *
71344
+ * Freezes the native float vertex mirror at add time (one
71345
+ * GetVertexData call): consumers (the compat GetGeometry surface)
71346
+ * read float vertices whose frame must match the scene transforms,
71347
+ * which are authored against the geometry AS CREATED. Later native
71348
+ * mutations that keep the vertex count (normalize's centering)
71349
+ * deliberately do NOT refresh the mirror, so every extraction path —
71350
+ * whole-model walk, per-product demand pump, parse-time preview —
71351
+ * serves the same creation-frame floats. Without this, paths that
71352
+ * first read vertices only after a centering mutation serve
71353
+ * per-geometry-shifted vertices against unshifted transforms
71354
+ * (Share's demand-path "scatter").
71355
+ *
70217
71356
  * @param mesh
70218
71357
  */
70219
71358
  add(mesh) {
71359
+ if (mesh.type === CanonicalMeshType.BUFFER_GEOMETRY) {
71360
+ mesh.geometry.GetVertexData();
71361
+ }
70220
71362
  this.meshes_.set(mesh.localID, mesh);
70221
71363
  }
70222
71364
  /**
@@ -70687,16 +71829,18 @@ var IfcMaterialCache = class {
70687
71829
 
70688
71830
  // compiled/src/ifc/ifc_step_model.js
70689
71831
  var indexerInstance = new StepTypeIndexer(EntityTypesIfcCount);
70690
- var IfcStepModel = class extends StepModelBase {
71832
+ var IfcStepModel = class extends step_model_base_default {
70691
71833
  /**
70692
71834
  * Construct this model given a buffer containing the data and the parsed data index on that,
70693
71835
  * adding the typeIndex on top of that.
70694
71836
  *
70695
- * @param buffer The buffer to values from.
71837
+ * @param buffer The buffer to values from, or `undefined` with `provider`
71838
+ * set for a windowed (streaming) source.
70696
71839
  * @param elementIndex The parsed index to elements in the STEP.
71840
+ * @param provider Optional pre-built buffer provider (windowed source).
70697
71841
  */
70698
- constructor(buffer, elementIndex) {
70699
- super(schema_ifc_gen_default, buffer, elementIndex);
71842
+ constructor(buffer, elementIndex, provider) {
71843
+ super(schema_ifc_gen_default, buffer, elementIndex, provider);
70700
71844
  this.externalMappingType = ifc_step_external_mapping_default;
70701
71845
  this.geometry = new IfcModelGeometry(this);
70702
71846
  this.voidGeometry = new IfcModelGeometry(this, true);
@@ -70706,11 +71850,330 @@ var IfcStepModel = class extends StepModelBase {
70706
71850
  this.materials = new IfcMaterialCache(this);
70707
71851
  this.voidMaterials = new IfcMaterialCache(this, true);
70708
71852
  this.elementTypeIDs = entity_types_ifc_gen_default;
70709
- this.typeIndex = indexerInstance.create(elementIndex);
71853
+ this.typeIndex = indexerInstance.createFor(elementIndex);
71854
+ }
71855
+ };
71856
+
71857
+ // compiled/src/step/parsing/columnar_index.js
71858
+ var COLUMN_UNDEFINED_TYPE = -1;
71859
+ var SEGMENT_ROWS = 64 * 1024;
71860
+ var ColumnarIndexSink = class {
71861
+ constructor() {
71862
+ this.segments_ = [];
71863
+ this.count_ = 0;
71864
+ this.retained_ = /* @__PURE__ */ new Map();
71865
+ this.expressIdsSorted_ = true;
71866
+ this.previousExpressID_ = 0;
71867
+ }
71868
+ /**
71869
+ * @return {number} Top-level records pushed so far.
71870
+ */
71871
+ get topLevelCount() {
71872
+ return this.count_;
71873
+ }
71874
+ /**
71875
+ * Encode one completed top-level record into the columns. The entry object
71876
+ * is not kept unless it carries children (inline entities / multi-mapping).
71877
+ *
71878
+ * @param entry The completed top-level index entry.
71879
+ */
71880
+ pushTopLevel(entry) {
71881
+ const localID = this.count_++;
71882
+ const segmentIndex = Math.floor(localID / SEGMENT_ROWS);
71883
+ const row = localID % SEGMENT_ROWS;
71884
+ if (segmentIndex === this.segments_.length) {
71885
+ this.segments_.push({
71886
+ address: new Uint32Array(SEGMENT_ROWS),
71887
+ length: new Uint32Array(SEGMENT_ROWS),
71888
+ typeID: new Int32Array(SEGMENT_ROWS),
71889
+ expressID: new Uint32Array(SEGMENT_ROWS)
71890
+ });
71891
+ }
71892
+ const segment = this.segments_[segmentIndex];
71893
+ segment.address[row] = entry.address;
71894
+ segment.length[row] = entry.length;
71895
+ segment.typeID[row] = entry.typeID === void 0 ? COLUMN_UNDEFINED_TYPE : entry.typeID;
71896
+ segment.expressID[row] = entry.expressID;
71897
+ if (entry.expressID < this.previousExpressID_) {
71898
+ this.expressIdsSorted_ = false;
71899
+ }
71900
+ this.previousExpressID_ = entry.expressID;
71901
+ if (entry.inlineEntities !== void 0 || entry.multiMapping !== void 0) {
71902
+ this.retained_.set(localID, entry);
71903
+ }
71904
+ }
71905
+ /**
71906
+ * Rewind to empty (the streaming builder's grow-and-restart). The first
71907
+ * segment is kept for reuse.
71908
+ */
71909
+ reset() {
71910
+ this.segments_.length = Math.min(this.segments_.length, 1);
71911
+ this.count_ = 0;
71912
+ this.retained_.clear();
71913
+ this.expressIdsSorted_ = true;
71914
+ this.previousExpressID_ = 0;
71915
+ }
71916
+ /**
71917
+ * Snapshot the columns pushed SO FAR into a self-contained prefix index,
71918
+ * without disturbing the sink — the parse can keep pushing afterwards and
71919
+ * a later snapshot/finalize sees the full data. Safe to call between the
71920
+ * cooperative parse's yields (the parser only suspends at top-level
71921
+ * record boundaries, where the sink is consistent). Top-level localIDs
71922
+ * are stable across snapshots (dense parse order), so consumers can carry
71923
+ * per-localID cursors from one snapshot to the next; inline-range
71924
+ * localIDs are NOT stable (the inline tail re-packs after the growing
71925
+ * top-level range) and must not be carried across snapshots.
71926
+ *
71927
+ * @return {StepIndexColumns} A prefix columnar index over the records
71928
+ * pushed so far.
71929
+ */
71930
+ snapshot() {
71931
+ return this.assemble_();
71932
+ }
71933
+ /**
71934
+ * Assemble the final columns: concatenate the top-level segments (one
71935
+ * column at a time, bounding transient overhead to a single column's
71936
+ * segments) and unfold retained inline entities into the inline range in
71937
+ * the model's exact unfold order.
71938
+ *
71939
+ * @return {StepIndexColumns} The finished columnar index.
71940
+ */
71941
+ finalize() {
71942
+ return this.assemble_();
71943
+ }
71944
+ /**
71945
+ * Shared assembly behind {@link snapshot} and {@link finalize} — pure
71946
+ * over the sink's current state.
71947
+ *
71948
+ * @return {StepIndexColumns} The assembled columnar index.
71949
+ */
71950
+ assemble_() {
71951
+ const topLevel = this.count_;
71952
+ const unfolded = [];
71953
+ for (const entry of this.retained_.values()) {
71954
+ if (entry.inlineEntities !== void 0) {
71955
+ unfolded.push(...entry.inlineEntities);
71956
+ }
71957
+ }
71958
+ for (let where = 0; where < unfolded.length; ++where) {
71959
+ const inlineEntities = unfolded[where].inlineEntities;
71960
+ if (inlineEntities !== void 0) {
71961
+ unfolded.push(...inlineEntities);
71962
+ }
71963
+ }
71964
+ const count = topLevel + unfolded.length;
71965
+ const address = concatColumn(this.segments_, "address", topLevel, count);
71966
+ const length = concatColumn(this.segments_, "length", topLevel, count);
71967
+ const typeID = new Int32Array(count);
71968
+ for (let segment = 0; segment * SEGMENT_ROWS < topLevel; ++segment) {
71969
+ const rows = Math.min(SEGMENT_ROWS, topLevel - segment * SEGMENT_ROWS);
71970
+ typeID.set(this.segments_[segment].typeID.subarray(0, rows), segment * SEGMENT_ROWS);
71971
+ }
71972
+ const expressID = concatColumn(this.segments_, "expressID", topLevel, topLevel);
71973
+ for (let where = 0; where < unfolded.length; ++where) {
71974
+ const entry = unfolded[where];
71975
+ const row = topLevel + where;
71976
+ address[row] = entry.address;
71977
+ length[row] = entry.length;
71978
+ typeID[row] = entry.typeID === void 0 ? COLUMN_UNDEFINED_TYPE : entry.typeID;
71979
+ }
71980
+ let complexEntries;
71981
+ for (const [localID, entry] of this.retained_) {
71982
+ if (entry.multiMapping !== void 0) {
71983
+ (complexEntries ??= /* @__PURE__ */ new Map()).set(localID, cloneIndexEntry(entry));
71984
+ }
71985
+ }
71986
+ return {
71987
+ address,
71988
+ length,
71989
+ typeID,
71990
+ expressID,
71991
+ count,
71992
+ firstInlineElement: topLevel,
71993
+ complexEntries,
71994
+ expressIdsSorted: this.expressIdsSorted_
71995
+ };
70710
71996
  }
70711
71997
  };
71998
+ function cloneIndexEntry(entry) {
71999
+ const clone = {
72000
+ address: entry.address,
72001
+ length: entry.length
72002
+ };
72003
+ if (entry.typeID !== void 0) {
72004
+ clone.typeID = entry.typeID;
72005
+ }
72006
+ if (entry.expressID !== void 0) {
72007
+ clone.expressID = entry.expressID;
72008
+ }
72009
+ if (entry.inlineEntities !== void 0) {
72010
+ clone.inlineEntities = entry.inlineEntities;
72011
+ }
72012
+ if (entry.multiMapping !== void 0) {
72013
+ clone.multiMapping = entry.multiMapping.map(cloneIndexEntry);
72014
+ }
72015
+ return clone;
72016
+ }
72017
+ function concatColumn(segments, column, rows, finalLength) {
72018
+ const result = new Uint32Array(finalLength);
72019
+ for (let segment = 0; segment * SEGMENT_ROWS < rows; ++segment) {
72020
+ const valid = Math.min(SEGMENT_ROWS, rows - segment * SEGMENT_ROWS);
72021
+ result.set(segments[segment][column].subarray(0, valid), segment * SEGMENT_ROWS);
72022
+ }
72023
+ return result;
72024
+ }
72025
+
72026
+ // compiled/src/step/parsing/streaming_index_builder.js
72027
+ function buildIndexStreaming(source, parser211, pool3, onRecordIndexed, sink) {
72028
+ const fileSize = source.byteLength;
72029
+ let windowBytes = Math.max(pool3, MIN_WINDOW);
72030
+ for (; ; ) {
72031
+ const window2 = new Uint8Array(windowBytes);
72032
+ let windowStartFile = 0;
72033
+ let windowLen = source.read(0, windowBytes, window2, 0);
72034
+ let bytesRead = windowLen;
72035
+ const input = new ParsingBuffer(window2, 0, windowLen);
72036
+ const [header, headerResult] = parser211.parseHeader(input);
72037
+ if (headerResult !== ParseResult.COMPLETE) {
72038
+ return {
72039
+ header,
72040
+ elements: [],
72041
+ result: headerResult,
72042
+ stats: { pool: pool3, windowBytes, slides: 0, maxRecordLen: 0, bytesRead }
72043
+ };
72044
+ }
72045
+ const slideThreshold = windowBytes >> 1;
72046
+ let slides = 0;
72047
+ let maxRecordLen = 0;
72048
+ let prevBoundaryFile = windowStartFile + input.cursor;
72049
+ const onRecordBoundary = (buffer) => {
72050
+ const cursor = buffer.cursor;
72051
+ const recordFileStart = windowStartFile + cursor;
72052
+ const recordLen = recordFileStart - prevBoundaryFile;
72053
+ if (recordLen > maxRecordLen) {
72054
+ maxRecordLen = recordLen;
72055
+ }
72056
+ prevBoundaryFile = recordFileStart;
72057
+ if (windowStartFile + windowLen >= fileSize) {
72058
+ return;
72059
+ }
72060
+ if (cursor < slideThreshold) {
72061
+ return;
72062
+ }
72063
+ const tail = windowLen - cursor;
72064
+ window2.copyWithin(0, cursor, windowLen);
72065
+ const want = windowBytes - tail;
72066
+ const got = source.read(windowStartFile + windowLen, want, window2, tail);
72067
+ bytesRead += got;
72068
+ windowLen = tail + got;
72069
+ windowStartFile = recordFileStart;
72070
+ buffer.rebaseWindow(window2, 0, windowLen, windowStartFile);
72071
+ ++slides;
72072
+ };
72073
+ const [index, result] = parser211.parseDataBlockStreamed(input, onRecordBoundary, onRecordIndexed, void 0, sink);
72074
+ const stoppedShort = result !== ParseResult.COMPLETE;
72075
+ const notAtEof = windowStartFile + windowLen < fileSize;
72076
+ if (stoppedShort && notAtEof) {
72077
+ windowBytes *= 2;
72078
+ sink?.reset();
72079
+ continue;
72080
+ }
72081
+ const lastRecordLen = windowStartFile + input.cursor - prevBoundaryFile;
72082
+ if (lastRecordLen > maxRecordLen) {
72083
+ maxRecordLen = lastRecordLen;
72084
+ }
72085
+ return {
72086
+ header,
72087
+ elements: index.elements,
72088
+ result,
72089
+ stats: { pool: pool3, windowBytes, slides, maxRecordLen, bytesRead }
72090
+ };
72091
+ }
72092
+ }
72093
+ var MIN_WINDOW = 4 * 1024;
72094
+ async function readSource(source, offset, length, into, intoOffset) {
72095
+ return await source.read(offset, length, into, intoOffset);
72096
+ }
72097
+ async function buildIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, sink, onProgress, yieldIntervalMs) {
72098
+ const fileSize = source.byteLength;
72099
+ let windowBytes = Math.max(pool3, MIN_WINDOW);
72100
+ for (; ; ) {
72101
+ const window2 = new Uint8Array(windowBytes);
72102
+ let windowStartFile = 0;
72103
+ let windowLen = await readSource(source, 0, windowBytes, window2, 0);
72104
+ let bytesRead = windowLen;
72105
+ const input = new ParsingBuffer(window2, 0, windowLen);
72106
+ const [header, headerResult] = parser211.parseHeader(input);
72107
+ if (headerResult !== ParseResult.COMPLETE) {
72108
+ return {
72109
+ header,
72110
+ elements: [],
72111
+ result: headerResult,
72112
+ stats: { pool: pool3, windowBytes, slides: 0, maxRecordLen: 0, bytesRead }
72113
+ };
72114
+ }
72115
+ const slideThreshold = windowBytes >> 1;
72116
+ let slides = 0;
72117
+ let maxRecordLen = 0;
72118
+ let prevBoundaryFile = windowStartFile + input.cursor;
72119
+ const onRecordBoundary = (buffer) => {
72120
+ const cursor = buffer.cursor;
72121
+ const recordFileStart = windowStartFile + cursor;
72122
+ const recordLen = recordFileStart - prevBoundaryFile;
72123
+ if (recordLen > maxRecordLen) {
72124
+ maxRecordLen = recordLen;
72125
+ }
72126
+ prevBoundaryFile = recordFileStart;
72127
+ if (windowStartFile + windowLen >= fileSize) {
72128
+ return;
72129
+ }
72130
+ if (cursor < slideThreshold) {
72131
+ return;
72132
+ }
72133
+ const tail = windowLen - cursor;
72134
+ window2.copyWithin(0, cursor, windowLen);
72135
+ const want = windowBytes - tail;
72136
+ const fillAt = windowStartFile + windowLen;
72137
+ return readSource(source, fillAt, want, window2, tail).then((got) => {
72138
+ bytesRead += got;
72139
+ windowLen = tail + got;
72140
+ windowStartFile = recordFileStart;
72141
+ buffer.rebaseWindow(window2, 0, windowLen, windowStartFile);
72142
+ ++slides;
72143
+ });
72144
+ };
72145
+ const progressTick = onProgress !== void 0 ? (cursor) => onProgress(windowStartFile + cursor) : void 0;
72146
+ const [index, result] = await parser211.parseDataBlockStreamedAsync(input, onRecordBoundary, onRecordIndexed, progressTick, sink, yieldIntervalMs);
72147
+ const stoppedShort = result !== ParseResult.COMPLETE;
72148
+ const notAtEof = windowStartFile + windowLen < fileSize;
72149
+ if (stoppedShort && notAtEof) {
72150
+ windowBytes *= 2;
72151
+ sink?.reset();
72152
+ continue;
72153
+ }
72154
+ const lastRecordLen = windowStartFile + input.cursor - prevBoundaryFile;
72155
+ if (lastRecordLen > maxRecordLen) {
72156
+ maxRecordLen = lastRecordLen;
72157
+ }
72158
+ return {
72159
+ header,
72160
+ elements: index.elements,
72161
+ result,
72162
+ stats: { pool: pool3, windowBytes, slides, maxRecordLen, bytesRead }
72163
+ };
72164
+ }
72165
+ }
72166
+ function buildColumnarIndexStreaming(source, parser211, pool3, onRecordIndexed, sink = new ColumnarIndexSink()) {
72167
+ const { header, result, stats } = buildIndexStreaming(source, parser211, pool3, onRecordIndexed, sink);
72168
+ return { header, columns: sink.finalize(), result, stats };
72169
+ }
72170
+ async function buildColumnarIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, onProgress, yieldIntervalMs, sink = new ColumnarIndexSink()) {
72171
+ const { header, result, stats } = await buildIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, sink, onProgress, yieldIntervalMs);
72172
+ return { header, columns: sink.finalize(), result, stats };
72173
+ }
70712
72174
 
70713
72175
  // compiled/src/ifc/ifc_step_parser.js
72176
+ var DEFAULT_STREAM_POOL_BYTES = 1024 * 1024;
70714
72177
  var IfcStepParser = class extends StepParser {
70715
72178
  /**
70716
72179
  * Construct the IFC step parser.
@@ -70743,6 +72206,61 @@ var IfcStepParser = class extends StepParser {
70743
72206
  const [itemIndex, parseResult2] = await this.parseDataBlockAsync(input, onProgress);
70744
72207
  return [parseResult2, new IfcStepModel(input.buffer, itemIndex.elements)];
70745
72208
  }
72209
+ /**
72210
+ * Build a model by streaming the source through a bounded moving window
72211
+ * (see buildIndexStreaming / M0) rather than parsing one resident buffer,
72212
+ * then backing the model with a windowed provider over `store` — so the
72213
+ * source is never held fully resident in the JS heap.
72214
+ *
72215
+ * `source` serves the parse (synchronous windowed reads — on a worker this
72216
+ * is an OPFS sync-access handle; in node/tests a file descriptor or buffer)
72217
+ * and `store` serves the model's post-parse property access (asynchronous
72218
+ * windowed reads paged in on demand — OPFS `File.slice()` in the browser).
72219
+ * Both view the same file bytes, so the file-absolute addresses the index
72220
+ * records resolve identically through either.
72221
+ *
72222
+ * NOTE (M1 scope): this delivers the bounded-memory *parse*. Synchronous
72223
+ * geometry extraction still needs its record ranges resident — as after
72224
+ * `spillSourceToExternalStore` — so a caller that extracts geometry must
72225
+ * `ensureResident` first (demand-driven geometry is M3). Property / index
72226
+ * access works directly via the async surfaces.
72227
+ *
72228
+ * @param source Synchronous byte source feeding the streaming parse.
72229
+ * @param store Async external store backing the windowed model.
72230
+ * @param opts Optional window sizing: `pool` (parse window),
72231
+ * `chunkBytes` / `maxResidentChunks` (model window).
72232
+ * @return {[ParseResult, IfcStepModel | undefined]} The parse result and
72233
+ * the windowed model.
72234
+ */
72235
+ parseStreamToModel(source, store, opts) {
72236
+ if (store.byteLength !== source.byteLength) {
72237
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match source byteLength ${source.byteLength}`);
72238
+ }
72239
+ const { columns, result } = buildColumnarIndexStreaming(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES);
72240
+ const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
72241
+ return [result, new IfcStepModel(void 0, columns, provider)];
72242
+ }
72243
+ /**
72244
+ * Cooperative twin of {@link parseStreamToModel}: the index build
72245
+ * yields to the event loop and can fill windows from an async
72246
+ * {@link ReadableByteSource} (an OPFS `File.slice()` store). The
72247
+ * model is still windowed — geometry extract must
72248
+ * `ensureResident` first.
72249
+ *
72250
+ * @param source Sync or async byte source feeding the parse.
72251
+ * @param store Async external store backing the windowed model.
72252
+ * @param opts Optional window sizing plus parse progress.
72253
+ * @return {Promise<[ParseResult, IfcStepModel | undefined]>} The
72254
+ * parse result and the windowed model.
72255
+ */
72256
+ async parseStreamToModelAsync(source, store, opts) {
72257
+ if (store.byteLength !== source.byteLength) {
72258
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match source byteLength ${source.byteLength}`);
72259
+ }
72260
+ const { columns, result } = await buildColumnarIndexStreamingAsync(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES, void 0, opts?.onProgress);
72261
+ const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
72262
+ return [result, new IfcStepModel(void 0, columns, provider)];
72263
+ }
70746
72264
  };
70747
72265
  IfcStepParser.Instance = new IfcStepParser();
70748
72266
  var ifc_step_parser_default = IfcStepParser;