@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
@@ -30,7 +30,7 @@ var import_node_process = require("node:process");
30
30
  var readline = __toESM(require("node:readline"), 1);
31
31
 
32
32
  // compiled/src/version/version.js
33
- var versionString = "Conway v1.389.1221";
33
+ var versionString = "Conway v1.394.1504";
34
34
 
35
35
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
36
36
  var wasmType = "";
@@ -374,10 +374,12 @@ var Logger = class _Logger {
374
374
  *
375
375
  * @param level - log level
376
376
  * @param message - log message
377
+ * @param expressID - record this entry is about, kept out of the message
378
+ * text so repeats dedupe into one entry (see the class doc)
377
379
  */
378
- static log(level, message) {
380
+ static log(level, message, expressID) {
379
381
  const baseMessage = message.split(" expressID: ")[0];
380
- const data = message.split(" expressID: ")[1];
382
+ const data = expressID !== void 0 ? String(expressID) : message.split(" expressID: ")[1];
381
383
  const index = _Logger.findLogIndex(baseMessage, level);
382
384
  let logEntry;
383
385
  let firstOccurrence = false;
@@ -399,7 +401,7 @@ var Logger = class _Logger {
399
401
  _Logger.logs.push(logEntry);
400
402
  }
401
403
  if (firstOccurrence && _Logger.isLevelEnabled(LOG_LEVEL_BY_NAME[level])) {
402
- _Logger.sink(level, baseMessage);
404
+ _Logger.sink(level, data !== void 0 ? `${baseMessage} expressID: ${data}` : baseMessage);
403
405
  }
404
406
  _Logger.proxies.forEach((proxy) => proxy.log(logEntry));
405
407
  }
@@ -504,16 +506,18 @@ var Logger = class _Logger {
504
506
  /**
505
507
  *
506
508
  * @param message - log message
509
+ * @param expressID - record this entry is about
507
510
  */
508
- static warning(message) {
509
- _Logger.log("warning", message);
511
+ static warning(message, expressID) {
512
+ _Logger.log("warning", message, expressID);
510
513
  }
511
514
  /**
512
515
  *
513
516
  * @param message - log message
517
+ * @param expressID - record this entry is about
514
518
  */
515
- static error(message) {
516
- _Logger.log("error", message);
519
+ static error(message, expressID) {
520
+ _Logger.log("error", message, expressID);
517
521
  }
518
522
  /**
519
523
  *
@@ -584,6 +588,20 @@ var environment_default = Environment;
584
588
 
585
589
  // compiled/src/core/progress.js
586
590
  function yieldToEventLoop() {
591
+ const scheduler = globalThis.scheduler;
592
+ if (typeof scheduler?.yield === "function") {
593
+ return scheduler.yield();
594
+ }
595
+ if (typeof MessageChannel === "function") {
596
+ return new Promise((resolve) => {
597
+ const channel = new MessageChannel();
598
+ channel.port1.onmessage = () => {
599
+ channel.port1.close();
600
+ resolve();
601
+ };
602
+ channel.port2.postMessage(null);
603
+ });
604
+ }
587
605
  return new Promise((resolve) => {
588
606
  setTimeout(resolve, 0);
589
607
  });
@@ -1113,6 +1131,19 @@ function copyOutOfResizable(view) {
1113
1131
  function decodeUtf8(view) {
1114
1132
  return decoder.decode(decodeNeedsCopy(view.buffer) ? view.slice() : view);
1115
1133
  }
1134
+ var strictUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
1135
+ function decodeStepString(view) {
1136
+ const bytes = decodeNeedsCopy(view.buffer) ? view.slice() : view;
1137
+ try {
1138
+ return strictUtf8Decoder.decode(bytes);
1139
+ } catch {
1140
+ let result = "";
1141
+ for (let where = 0; where < bytes.length; ++where) {
1142
+ result += String.fromCharCode(bytes[where]);
1143
+ }
1144
+ return result;
1145
+ }
1146
+ }
1116
1147
  var shimInstalled = false;
1117
1148
  function installResizableTextDecoderShim() {
1118
1149
  if (shimInstalled || typeof TextDecoder === "undefined") {
@@ -1286,6 +1317,37 @@ var ParsingBuffer = class {
1286
1317
  this.buffer = buffer;
1287
1318
  this.end = endOffset;
1288
1319
  }
1320
+ /**
1321
+ * Streaming support: repoint this buffer at a fresh window over the same
1322
+ * logical stream while keeping `address` file-absolute.
1323
+ *
1324
+ * A moving-window parse holds only a slice of the source in memory at a
1325
+ * time. Between top-level records (where the rewind stack is empty) the
1326
+ * driver slides the window forward: it copies the unconsumed tail to the
1327
+ * front of a reused buffer, appends freshly-read bytes, and calls this to
1328
+ * repoint the parser. `addressBase` is the file offset that window index 0
1329
+ * now corresponds to; we store it as a negative initial offset so
1330
+ * `address` ( = cursor − initialOffset ) stays the file-absolute value the
1331
+ * non-streaming parse would have produced.
1332
+ *
1333
+ * Must only be called with the rewind stack empty (i.e. at a record
1334
+ * boundary) — the stack holds window-relative cursors that a slide would
1335
+ * invalidate. Throws otherwise.
1336
+ *
1337
+ * @param buffer The new window buffer.
1338
+ * @param cursorInWindow The cursor position within the new window.
1339
+ * @param endInWindow The count of valid bytes in the new window.
1340
+ * @param addressBase The file offset that window index 0 maps to.
1341
+ */
1342
+ rebaseWindow(buffer, cursorInWindow, endInWindow, addressBase) {
1343
+ if (this.rewindStack_.length !== 0) {
1344
+ throw Error("rebaseWindow called mid-transaction (rewind stack non-empty)");
1345
+ }
1346
+ this.buffer = buffer;
1347
+ this.cursor_ = cursorInWindow;
1348
+ this.initialOffset_ = -addressBase;
1349
+ this.end = endInWindow;
1350
+ }
1289
1351
  /**
1290
1352
  * Construct this with a buffer, initial offset into the buffer and an end offset.
1291
1353
  *
@@ -1769,14 +1831,14 @@ var StepStringParser = class extends ParsingDfa16Table {
1769
1831
  if (nextCursor < endCursor && input2[nextCursor] === QUOTE) {
1770
1832
  result ??= "";
1771
1833
  if (cursor > reificationIndex) {
1772
- result += decodeUtf8(input2.subarray(reificationIndex, cursor - 1));
1834
+ result += decodeStepString(input2.subarray(reificationIndex, cursor - 1));
1773
1835
  }
1774
1836
  result += "'";
1775
1837
  cursor = nextCursor + 1;
1776
1838
  reificationIndex = cursor;
1777
1839
  } else {
1778
1840
  result ??= "";
1779
- result += decodeUtf8(input2.subarray(reificationIndex, cursor));
1841
+ result += decodeStepString(input2.subarray(reificationIndex, cursor));
1780
1842
  return result;
1781
1843
  }
1782
1844
  }
@@ -1802,7 +1864,7 @@ var StepStringParser = class extends ParsingDfa16Table {
1802
1864
  const nextChar2 = input2[nextCursor2];
1803
1865
  if (nextChar2 !== BSLASH) {
1804
1866
  result ??= "";
1805
- result += decodeUtf8(input2.subarray(reificationIndex, cursor));
1867
+ result += decodeStepString(input2.subarray(reificationIndex, cursor));
1806
1868
  cursor = nextCursor2 + 1;
1807
1869
  break;
1808
1870
  }
@@ -1815,7 +1877,7 @@ var StepStringParser = class extends ParsingDfa16Table {
1815
1877
  return result;
1816
1878
  }
1817
1879
  result ??= "";
1818
- result += decodeUtf8(input2.subarray(reificationIndex, cursor));
1880
+ result += decodeStepString(input2.subarray(reificationIndex, cursor));
1819
1881
  codePage = nextChar3 - A2;
1820
1882
  cursor = nextCursor3 + 1;
1821
1883
  reificationIndex = cursor;
@@ -1829,7 +1891,7 @@ var StepStringParser = class extends ParsingDfa16Table {
1829
1891
  const nextChar2 = input2[nextCursor2];
1830
1892
  if (nextChar2 !== BSLASH) {
1831
1893
  result ??= "";
1832
- result += decodeUtf8(input2.subarray(reificationIndex, cursor));
1894
+ result += decodeStepString(input2.subarray(reificationIndex, cursor));
1833
1895
  cursor = nextCursor2 + 1;
1834
1896
  break;
1835
1897
  }
@@ -1839,7 +1901,7 @@ var StepStringParser = class extends ParsingDfa16Table {
1839
1901
  }
1840
1902
  const nextChar3 = input2[nextCursor3];
1841
1903
  result ??= "";
1842
- result += decodeUtf8(input2.subarray(reificationIndex, cursor));
1904
+ result += decodeStepString(input2.subarray(reificationIndex, cursor));
1843
1905
  if (nextChar3 < 127) {
1844
1906
  result += String.fromCharCode(nextChar3);
1845
1907
  } else if (nextChar >= 161 && nextChar <= 255) {
@@ -1858,7 +1920,7 @@ var StepStringParser = class extends ParsingDfa16Table {
1858
1920
  }
1859
1921
  const nextChar2 = input2[nextCursor2];
1860
1922
  result ??= "";
1861
- result += decodeUtf8(input2.subarray(reificationIndex, cursor));
1923
+ result += decodeStepString(input2.subarray(reificationIndex, cursor));
1862
1924
  const hexParserTil0 = (count) => {
1863
1925
  if (nextCursor2 + 1 >= endCursor || input2[nextCursor2 + 1] !== BSLASH) {
1864
1926
  return false;
@@ -2205,6 +2267,18 @@ function* stepExtractArray(buffer, cursor, endCursor) {
2205
2267
  throw new Error("Unterminated array");
2206
2268
  }
2207
2269
  }
2270
+ function stepEnterTypedValue(buffer, cursor, endCursor, typeName) {
2271
+ const identifierEnd = identifierParser.match(buffer, cursor, endCursor);
2272
+ if (identifierEnd === void 0 || identifierEnd - cursor !== typeName.length) {
2273
+ return cursor;
2274
+ }
2275
+ for (let where = 0; where < typeName.length; ++where) {
2276
+ if (buffer[cursor + where] !== typeName.charCodeAt(where)) {
2277
+ return cursor;
2278
+ }
2279
+ }
2280
+ return stepExtractInlineElemement(buffer, cursor, endCursor) ?? cursor;
2281
+ }
2208
2282
  function stepExtractInlineElemement(buffer, cursor, endCursor) {
2209
2283
  const identifier = identifierParser.match(buffer, cursor, endCursor);
2210
2284
  if (identifier === void 0) {
@@ -2535,9 +2609,87 @@ var StepParser = class extends StepHeaderParser {
2535
2609
  if (next.done === true) {
2536
2610
  return next.value;
2537
2611
  }
2612
+ if (typeof next.value === "number") {
2613
+ onProgress?.(next.value);
2614
+ }
2615
+ }
2616
+ }
2617
+ /**
2618
+ * Streaming driver over parseDataBlockIncremental: identical parse (same
2619
+ * generator body) but invokes `onRecordBoundary` at every top-level record
2620
+ * boundary so a caller feeding the parser from a moving window can slide
2621
+ * that window forward while the rewind stack is empty. See
2622
+ * streaming_index_builder.ts for the coordinator that owns the window.
2623
+ *
2624
+ * @param input The input parsing buffer, positioned at the data section.
2625
+ * @param onRecordBoundary Called at each top-level record boundary with the
2626
+ * buffer; the callback may rebase the buffer's window in place. Must be
2627
+ * synchronous on this driver — a returned Promise is a caller bug.
2628
+ * @param onRecordIndexed Called as each top-level record is indexed, with
2629
+ * its localID, expressID, typeID (0 for external-mapping records) and the
2630
+ * record's bytes as an un-materialised `(buffer, byteOffset, byteLength)`
2631
+ * window view — the seam for incremental semantic consumers (type index,
2632
+ * roots registry, names skeleton). See {@link RecordEventHandler} for the
2633
+ * window-lifetime rule. Must be synchronous and cheap; expensive work
2634
+ * belongs on a demand queue, not the parse path.
2635
+ * @param onProgress Optional byte-cursor progress callback.
2636
+ * @return {BlockParseResult} The parsing result, including the index and result enum.
2637
+ */
2638
+ parseDataBlockStreamed(input2, onRecordBoundary, onRecordIndexed, onProgress, sink) {
2639
+ const parser211 = this.parseDataBlockIncremental(input2, onRecordBoundary, onRecordIndexed, sink);
2640
+ while (true) {
2641
+ const next = parser211.next();
2642
+ if (next.done === true) {
2643
+ return next.value;
2644
+ }
2645
+ if (typeof next.value !== "number") {
2646
+ throw new Error("parseDataBlockStreamed: async window slide requires parseDataBlockStreamedAsync");
2647
+ }
2538
2648
  onProgress?.(next.value);
2539
2649
  }
2540
2650
  }
2651
+ /**
2652
+ * Cooperative variant of parseDataBlockStreamed: identical parse and
2653
+ * window-slide behaviour (same generator body, same boundary callback),
2654
+ * but periodically awaits a macrotask so the event loop can run —
2655
+ * browsers repaint progress UI during a large streamed parse instead of
2656
+ * flagging the tab as stalled. Issue #301 §2 for the streamed path.
2657
+ *
2658
+ * @param input The input parsing buffer, positioned at the data section.
2659
+ * @param onRecordBoundary Called at each top-level record boundary with the
2660
+ * buffer; the callback may rebase the buffer's window in place. May return
2661
+ * a Promise when the slide itself is I/O (an async ByteSource); this
2662
+ * driver awaits it before the next record is lexed.
2663
+ * @param onRecordIndexed Called as each top-level record is indexed — see
2664
+ * parseDataBlockStreamed.
2665
+ * @param onProgress Optional byte-cursor progress callback.
2666
+ * @param sink Optional index sink (columnar builds).
2667
+ * @param yieldIntervalMs Minimum ms between event-loop yields.
2668
+ * @return {Promise<BlockParseResult>} The parsing result, including the
2669
+ * index and result enum.
2670
+ */
2671
+ async parseDataBlockStreamedAsync(input2, onRecordBoundary, onRecordIndexed, onProgress, sink, yieldIntervalMs = DEFAULT_PARSE_YIELD_INTERVAL_MS) {
2672
+ const parser211 = this.parseDataBlockIncremental(input2, onRecordBoundary, onRecordIndexed, sink);
2673
+ let lastYield = Date.now();
2674
+ while (true) {
2675
+ const next = parser211.next();
2676
+ if (next.done === true) {
2677
+ return next.value;
2678
+ }
2679
+ if (typeof next.value !== "number") {
2680
+ await next.value;
2681
+ continue;
2682
+ }
2683
+ const progressed = onProgress?.(next.value);
2684
+ if (progressed !== void 0 && typeof progressed.then === "function") {
2685
+ await progressed;
2686
+ }
2687
+ if (Date.now() - lastYield >= yieldIntervalMs) {
2688
+ await yieldToEventLoop();
2689
+ lastYield = Date.now();
2690
+ }
2691
+ }
2692
+ }
2541
2693
  /**
2542
2694
  * Cooperative variant of parseDataBlock: identical parse (same generator
2543
2695
  * body), but periodically awaits a macrotask so the event loop can run —
@@ -2558,7 +2710,9 @@ var StepParser = class extends StepHeaderParser {
2558
2710
  if (next.done === true) {
2559
2711
  return next.value;
2560
2712
  }
2561
- onProgress?.(next.value);
2713
+ if (typeof next.value === "number") {
2714
+ onProgress?.(next.value);
2715
+ }
2562
2716
  if (Date.now() - lastYield >= yieldIntervalMs) {
2563
2717
  await yieldToEventLoop();
2564
2718
  lastYield = Date.now();
@@ -2575,8 +2729,14 @@ var StepParser = class extends StepHeaderParser {
2575
2729
  * @yields {number} The current byte cursor within the input buffer.
2576
2730
  * @return {BlockParseResult} The parsing result, including the index and result enum.
2577
2731
  */
2578
- *parseDataBlockIncremental(input2) {
2732
+ *parseDataBlockIncremental(input2, onRecordBoundary, onRecordIndexed, sink) {
2579
2733
  const indexResult = { elements: [] };
2734
+ let topLevelCount = 0;
2735
+ const pushEntry = sink !== void 0 ? (entry) => {
2736
+ sink.pushTopLevel(entry);
2737
+ } : (entry) => {
2738
+ indexResult.elements.push(entry);
2739
+ };
2580
2740
  const match = input2.match;
2581
2741
  const comment = () => match(commentParser2);
2582
2742
  const whitespace = () => {
@@ -2622,7 +2782,7 @@ var StepParser = class extends StepHeaderParser {
2622
2782
  return syntaxError();
2623
2783
  }
2624
2784
  whitespace();
2625
- const startElement = input2.cursor;
2785
+ const startElement = input2.address;
2626
2786
  let stackDepth = 1;
2627
2787
  const savedInlineElements = inlineElements;
2628
2788
  inlineElements = void 0;
@@ -2716,6 +2876,10 @@ var StepParser = class extends StepHeaderParser {
2716
2876
  if ((++parsedElementCount & PARSE_PROGRESS_ELEMENT_MASK) === 0) {
2717
2877
  yield input2.cursor;
2718
2878
  }
2879
+ const slide = onRecordBoundary?.(input2);
2880
+ if (slide !== void 0 && typeof slide.then === "function") {
2881
+ yield slide;
2882
+ }
2719
2883
  if (!charws(HASH2)) {
2720
2884
  if (tokenws(END_SECTION)) {
2721
2885
  return parseResult2(ParseResult.COMPLETE);
@@ -2738,7 +2902,7 @@ var StepParser = class extends StepHeaderParser {
2738
2902
  }
2739
2903
  whitespace();
2740
2904
  inlineElements = void 0;
2741
- const startElement2 = input2.cursor;
2905
+ const startElement2 = input2.address;
2742
2906
  while (!charws(CLOSE_PAREN2)) {
2743
2907
  input2.begin();
2744
2908
  const elementResult = parseInlineElement(expressID);
@@ -2751,7 +2915,7 @@ var StepParser = class extends StepHeaderParser {
2751
2915
  if (!charws(SEMICOLON)) {
2752
2916
  return syntaxError();
2753
2917
  }
2754
- indexResult.elements.push({
2918
+ pushEntry({
2755
2919
  address: startElement2,
2756
2920
  length: input2.address - startElement2,
2757
2921
  typeID: 0,
@@ -2760,6 +2924,11 @@ var StepParser = class extends StepHeaderParser {
2760
2924
  inlineEntities: inlineElements,
2761
2925
  multiMapping: multiElements
2762
2926
  });
2927
+ {
2928
+ const recordLen = input2.address - startElement2;
2929
+ onRecordIndexed?.(topLevelCount, expressID, 0, input2.buffer, input2.cursor - recordLen, recordLen);
2930
+ }
2931
+ ++topLevelCount;
2763
2932
  multiElements = void 0;
2764
2933
  continue;
2765
2934
  }
@@ -2769,7 +2938,7 @@ var StepParser = class extends StepHeaderParser {
2769
2938
  return syntaxError();
2770
2939
  }
2771
2940
  whitespace();
2772
- const startElement = input2.cursor;
2941
+ const startElement = input2.address;
2773
2942
  let stackDepth = 1;
2774
2943
  inlineElements = void 0;
2775
2944
  while (stackDepth > 0) {
@@ -2796,9 +2965,6 @@ var StepParser = class extends StepHeaderParser {
2796
2965
  input2.begin();
2797
2966
  const elementResult = parseInlineElement();
2798
2967
  if (elementResult !== void 0) {
2799
- for (const element of elementResult[0].elements) {
2800
- element.expressID = expressID;
2801
- }
2802
2968
  input2.rollback();
2803
2969
  if (tokenws(INF)) {
2804
2970
  break;
@@ -2842,13 +3008,18 @@ var StepParser = class extends StepHeaderParser {
2842
3008
  if (!charws(SEMICOLON)) {
2843
3009
  return syntaxError();
2844
3010
  }
2845
- indexResult.elements.push({
3011
+ pushEntry({
2846
3012
  address: startElement,
2847
3013
  length: input2.address - startElement,
2848
3014
  typeID: foundItem,
2849
3015
  expressID,
2850
3016
  inlineEntities: inlineElements
2851
3017
  });
3018
+ {
3019
+ const recordLen = input2.address - startElement;
3020
+ onRecordIndexed?.(topLevelCount, expressID, foundItem, input2.buffer, input2.cursor - recordLen, recordLen);
3021
+ }
3022
+ ++topLevelCount;
2852
3023
  }
2853
3024
  return parseResult2(ParseResult.INCOMPLETE);
2854
3025
  }
@@ -4257,6 +4428,70 @@ var EntityTypesIfc;
4257
4428
  var EntityTypesIfcCount = 909;
4258
4429
  var entity_types_ifc_gen_default = EntityTypesIfc;
4259
4430
 
4431
+ // compiled/src/step/parsing/express_ref_scan.js
4432
+ var HASH3 = 35;
4433
+ var QUOTE4 = 39;
4434
+ var DQUOTE = 34;
4435
+ var ZERO5 = 48;
4436
+ var NINE2 = 57;
4437
+ var SLASH3 = 47;
4438
+ var STAR2 = 42;
4439
+ function scanExpressRefs(bytes, from = 0, length = bytes.length - from) {
4440
+ const refs = [];
4441
+ const seen = /* @__PURE__ */ new Set();
4442
+ const end = Math.min(from + length, bytes.length);
4443
+ let cursor = from;
4444
+ while (cursor < end) {
4445
+ const byte = bytes[cursor];
4446
+ if (byte === QUOTE4) {
4447
+ cursor = skipQuoted_(bytes, cursor + 1, end, QUOTE4, true);
4448
+ continue;
4449
+ }
4450
+ if (byte === DQUOTE) {
4451
+ cursor = skipQuoted_(bytes, cursor + 1, end, DQUOTE, false);
4452
+ continue;
4453
+ }
4454
+ if (byte === SLASH3 && cursor + 1 < end && bytes[cursor + 1] === STAR2) {
4455
+ cursor += 2;
4456
+ while (cursor + 1 < end && !(bytes[cursor] === STAR2 && bytes[cursor + 1] === SLASH3)) {
4457
+ ++cursor;
4458
+ }
4459
+ cursor += 2;
4460
+ continue;
4461
+ }
4462
+ if (byte === HASH3) {
4463
+ let value = 0;
4464
+ let digit = cursor + 1;
4465
+ while (digit < end && bytes[digit] >= ZERO5 && bytes[digit] <= NINE2) {
4466
+ value = value * 10 + (bytes[digit] - ZERO5);
4467
+ ++digit;
4468
+ }
4469
+ if (digit > cursor + 1 && value !== 0 && !seen.has(value)) {
4470
+ seen.add(value);
4471
+ refs.push(value);
4472
+ }
4473
+ cursor = digit;
4474
+ continue;
4475
+ }
4476
+ ++cursor;
4477
+ }
4478
+ return refs;
4479
+ }
4480
+ function skipQuoted_(bytes, from, end, quote, doubledEscape) {
4481
+ let cursor = from;
4482
+ while (cursor < end) {
4483
+ if (bytes[cursor] === quote) {
4484
+ if (doubledEscape && cursor + 1 < end && bytes[cursor + 1] === quote) {
4485
+ cursor += 2;
4486
+ continue;
4487
+ }
4488
+ return cursor + 1;
4489
+ }
4490
+ ++cursor;
4491
+ }
4492
+ return end;
4493
+ }
4494
+
4260
4495
  // compiled/src/step/step_buffer_provider.js
4261
4496
  var DEFAULT_CHUNK_BYTES = 4 * 1024 * 1024;
4262
4497
  var DEFAULT_MAX_RESIDENT_CHUNKS = 16;
@@ -4437,7 +4672,7 @@ var WindowedStepBufferProvider = class {
4437
4672
  const firstChunk = Math.floor(address / chunkBytes);
4438
4673
  const lastChunk = Math.floor((address + Math.max(length, 1) - 1) / chunkBytes);
4439
4674
  for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; ++chunkIndex) {
4440
- this.ensurePins_.set(chunkIndex, (this.ensurePins_.get(chunkIndex) ?? 0) + 1);
4675
+ this.addPin_(chunkIndex, 1);
4441
4676
  }
4442
4677
  try {
4443
4678
  const loads = [];
@@ -4480,15 +4715,63 @@ var WindowedStepBufferProvider = class {
4480
4715
  }
4481
4716
  } finally {
4482
4717
  for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; ++chunkIndex) {
4483
- const pins = this.ensurePins_.get(chunkIndex) ?? 0;
4484
- if (pins <= 1) {
4485
- this.ensurePins_.delete(chunkIndex);
4486
- } else {
4487
- this.ensurePins_.set(chunkIndex, pins - 1);
4488
- }
4718
+ this.addPin_(chunkIndex, -1);
4489
4719
  }
4490
4720
  }
4491
4721
  }
4722
+ /**
4723
+ * Hold a range against LRU eviction until {@link unpinRange}.
4724
+ *
4725
+ * @param address Absolute start of the range.
4726
+ * @param length Length of the range.
4727
+ */
4728
+ pinRange(address, length) {
4729
+ for (const chunkIndex of this.chunkSpan_(address, length)) {
4730
+ this.addPin_(chunkIndex, 1);
4731
+ }
4732
+ }
4733
+ /**
4734
+ * Drop one {@link pinRange} hold.
4735
+ *
4736
+ * @param address Absolute start of the range.
4737
+ * @param length Length of the range.
4738
+ */
4739
+ unpinRange(address, length) {
4740
+ for (const chunkIndex of this.chunkSpan_(address, length)) {
4741
+ this.addPin_(chunkIndex, -1);
4742
+ }
4743
+ }
4744
+ /**
4745
+ * Chunk indices covering `[address, address + length)`.
4746
+ *
4747
+ * @param address Absolute start.
4748
+ * @param length Length in bytes.
4749
+ * @return {number[]} Inclusive chunk indices.
4750
+ */
4751
+ chunkSpan_(address, length) {
4752
+ const chunkBytes = this.chunkBytes_;
4753
+ const firstChunk = Math.floor(address / chunkBytes);
4754
+ const lastChunk = Math.floor((address + Math.max(length, 1) - 1) / chunkBytes);
4755
+ const span = [];
4756
+ for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; ++chunkIndex) {
4757
+ span.push(chunkIndex);
4758
+ }
4759
+ return span;
4760
+ }
4761
+ /**
4762
+ * Adjust a chunk's pin count, deleting the entry at zero.
4763
+ *
4764
+ * @param chunkIndex The chunk.
4765
+ * @param delta +1 pin or -1 unpin.
4766
+ */
4767
+ addPin_(chunkIndex, delta) {
4768
+ const pins = (this.ensurePins_.get(chunkIndex) ?? 0) + delta;
4769
+ if (pins <= 0) {
4770
+ this.ensurePins_.delete(chunkIndex);
4771
+ } else {
4772
+ this.ensurePins_.set(chunkIndex, pins);
4773
+ }
4774
+ }
4492
4775
  };
4493
4776
 
4494
4777
  // compiled/src/step/parsing/step_vtable_builder.js
@@ -4554,6 +4837,101 @@ var StepVtableBuilder = class {
4554
4837
  }
4555
4838
  };
4556
4839
 
4840
+ // compiled/src/step/parsing/uint32_sink.js
4841
+ var OPEN_PAREN3 = parsing_constants_default.OPEN_PAREN;
4842
+ var CLOSE_PAREN3 = parsing_constants_default.CLOSE_PAREN;
4843
+ var COMMA3 = parsing_constants_default.COMMA;
4844
+ var ZERO6 = parsing_constants_default.ZERO;
4845
+ var WHITESPACE4 = parsing_constants_default.WHITE_SPACE_SET;
4846
+ function extractIntegerArrayAt(buffer, cursor, endCursor, sink) {
4847
+ const marked = sink.length;
4848
+ const fast = extractUnsignedIntegerListAt(buffer, cursor, endCursor, sink);
4849
+ if (fast !== void 0) {
4850
+ return fast;
4851
+ }
4852
+ sink.truncate(marked);
4853
+ if (stepExtractOptional(buffer, cursor, endCursor) === null) {
4854
+ return 0;
4855
+ }
4856
+ let count = 0;
4857
+ let signedCursor0 = stepExtractArrayBegin(buffer, cursor, endCursor);
4858
+ let readCursor = Math.abs(signedCursor0);
4859
+ while (signedCursor0 >= 0) {
4860
+ const value = stepExtractNumber(buffer, readCursor, endCursor);
4861
+ if (value === void 0) {
4862
+ throw new Error("Value in STEP was incorrectly typed");
4863
+ }
4864
+ readCursor = skipValue(buffer, readCursor, endCursor);
4865
+ sink.push(value);
4866
+ ++count;
4867
+ signedCursor0 = stepExtractArrayToken(buffer, readCursor, endCursor);
4868
+ readCursor = Math.abs(signedCursor0);
4869
+ }
4870
+ return count;
4871
+ }
4872
+ function extractUnsignedIntegerListAt(buffer, cursor, endCursor, sink) {
4873
+ const marked = sink.length;
4874
+ while (cursor < endCursor && WHITESPACE4.has(buffer[cursor])) {
4875
+ ++cursor;
4876
+ }
4877
+ if (cursor >= endCursor) {
4878
+ return void 0;
4879
+ }
4880
+ if (buffer[cursor] === parsing_constants_default.DOLLAR) {
4881
+ return 0;
4882
+ }
4883
+ if (buffer[cursor] !== OPEN_PAREN3) {
4884
+ return void 0;
4885
+ }
4886
+ ++cursor;
4887
+ let count = 0;
4888
+ while (cursor < endCursor) {
4889
+ while (cursor < endCursor && WHITESPACE4.has(buffer[cursor])) {
4890
+ ++cursor;
4891
+ }
4892
+ if (cursor >= endCursor) {
4893
+ sink.truncate(marked);
4894
+ return void 0;
4895
+ }
4896
+ if (buffer[cursor] === CLOSE_PAREN3) {
4897
+ return count;
4898
+ }
4899
+ if (count > 0) {
4900
+ if (buffer[cursor] !== COMMA3) {
4901
+ sink.truncate(marked);
4902
+ return void 0;
4903
+ }
4904
+ ++cursor;
4905
+ while (cursor < endCursor && WHITESPACE4.has(buffer[cursor])) {
4906
+ ++cursor;
4907
+ }
4908
+ if (cursor >= endCursor) {
4909
+ sink.truncate(marked);
4910
+ return void 0;
4911
+ }
4912
+ }
4913
+ const digit = buffer[cursor] - ZERO6;
4914
+ if (digit < 0 || digit > 9) {
4915
+ sink.truncate(marked);
4916
+ return void 0;
4917
+ }
4918
+ let value = digit;
4919
+ ++cursor;
4920
+ while (cursor < endCursor) {
4921
+ const next = buffer[cursor] - ZERO6;
4922
+ if (next < 0 || next > 9) {
4923
+ break;
4924
+ }
4925
+ value = value * 10 + next;
4926
+ ++cursor;
4927
+ }
4928
+ sink.push(value);
4929
+ ++count;
4930
+ }
4931
+ sink.truncate(marked);
4932
+ return void 0;
4933
+ }
4934
+
4557
4935
  // compiled/src/indexing/index_set_constants.js
4558
4936
  var IndexSetConstants = class {
4559
4937
  };
@@ -4915,23 +5293,54 @@ var InterpolationSearchTable32 = class {
4915
5293
  };
4916
5294
 
4917
5295
  // compiled/src/step/step_model_base.js
4918
- var StepModelBase = class {
5296
+ var StepModelBase = class _StepModelBase {
4919
5297
  /**
4920
5298
  * Construct this step model with its matching schema, a buffer to read from and an element index.
4921
5299
  *
4922
5300
  * @param schema The Step schema this is based on.
4923
- * @param buffer_ The buffer to read this from.
5301
+ * @param buffer_ The buffer to read this from. Pass `undefined` together
5302
+ * with `provider` to build a model whose source is windowed from
5303
+ * construction (e.g. a streaming open — see buildModelStreaming); the
5304
+ * synchronous read paths (geometry extraction) then require the relevant
5305
+ * ranges to be resident, exactly as after `spillSourceToExternalStore`.
4924
5306
  * @param elementIndex The element index for this, parsed or deserialized - note this takes
4925
5307
  * ownership of this array in the sense it will modify values/unfold inline elements etc.
5308
+ * @param provider Optional pre-built buffer provider. When omitted, a
5309
+ * resident provider over `buffer_` is used (the classic path).
4926
5310
  */
4927
- constructor(schema, buffer_, elementIndex) {
5311
+ constructor(schema, buffer_, elementIndex, provider) {
4928
5312
  this.schema = schema;
4929
5313
  this.buffer_ = buffer_;
4930
5314
  this.vtableBuilder_ = new StepVtableBuilder();
4931
5315
  this.descriptorCache_ = [];
4932
5316
  this.elementMemoization = true;
4933
5317
  this.nullOnErrors = true;
4934
- this.bufferProvider_ = new ResidentStepBufferProvider(buffer_);
5318
+ this.bufferProvider_ = provider ?? new ResidentStepBufferProvider(buffer_);
5319
+ if (!Array.isArray(elementIndex)) {
5320
+ const columns = elementIndex;
5321
+ const firstInline = columns.firstInlineElement;
5322
+ const inlineCount = columns.count - firstInline;
5323
+ const inlineElementTable2 = new Uint32Array(inlineCount << 1);
5324
+ for (let where2 = 0; where2 < inlineCount; ++where2) {
5325
+ inlineElementTable2[where2 << 1] = firstInline + where2;
5326
+ inlineElementTable2[(where2 << 1) + 1] = columns.address[firstInline + where2];
5327
+ }
5328
+ this.inlineAddressMap_ = new InterpolationSearchTable32(inlineElementTable2, true);
5329
+ const expressIdTable2 = new Uint32Array(firstInline << 1);
5330
+ for (let where2 = 0; where2 < firstInline; ++where2) {
5331
+ expressIdTable2[where2 << 1] = where2;
5332
+ expressIdTable2[(where2 << 1) + 1] = columns.expressID[where2];
5333
+ }
5334
+ this.expressIDMap_ = new InterpolationSearchTable32(expressIdTable2, columns.expressIdsSorted);
5335
+ this.address_ = columns.address;
5336
+ this.length_ = columns.length;
5337
+ this.typeID_ = columns.typeID;
5338
+ this.expressID_ = columns.expressID;
5339
+ this.count_ = columns.count;
5340
+ this.firstInlineElement_ = firstInline;
5341
+ this.complexEntries_ = columns.complexEntries;
5342
+ return;
5343
+ }
4935
5344
  const localElementIndex = elementIndex;
4936
5345
  let where = 0;
4937
5346
  const firstInlineElement = localElementIndex.length;
@@ -5074,11 +5483,94 @@ var StepModelBase = class {
5074
5483
  }
5075
5484
  }
5076
5485
  /**
5077
- * Populate a raw vtable entry for a particular element, extra
5486
+ * Resolve an express ID to a local ID, using `hintLocalID + 1` when
5487
+ * the next record is the one we want. Tessellated Faces lists are
5488
+ * sequential (PSB: every faceset), so this turns 9.1M interpolation
5489
+ * searches into one per faceset.
5078
5490
  *
5079
- * @param element The raw elment to populate the vtable entry for.
5080
- * @return {boolean} Did the vtable entry populate correctly?
5491
+ * @param expressID The referenced record.
5492
+ * @param hintLocalID Local ID of the previous resolve, if any.
5493
+ * @return {number | undefined} The local ID, or undefined if unknown.
5494
+ */
5495
+ resolveExpressID(expressID, hintLocalID) {
5496
+ if (hintLocalID !== void 0) {
5497
+ const next = hintLocalID + 1;
5498
+ if (next < this.firstInlineElement_ && this.expressID_[next] === expressID) {
5499
+ return next;
5500
+ }
5501
+ }
5502
+ return this.expressIDMap_.get(expressID);
5503
+ }
5504
+ /**
5505
+ * Append a local record's unsigned-integer list field into `sink`
5506
+ * without an express-ID lookup. The reference-level twin of
5507
+ * `StepEntityBase.extractIntegerArrayInto`, for hot loops that walk
5508
+ * millions of small records (tessellated facesets) where constructing
5509
+ * an entity per record dominates. It deliberately handles only the
5510
+ * simple case and reports failure otherwise, so callers keep a
5511
+ * correct fallback rather than this growing subtle special cases:
5512
+ * the record must be single-class (no multi-mapping) and exactly
5513
+ * `expectedTypeID`.
5514
+ *
5515
+ * Field 0 is the data-block start the parser stored in `address_`
5516
+ * (after `TYPE(`). Reading it from the columns skips the descriptor
5517
+ * and vtable `entry()` would retain — on a 9 M-face model those are
5518
+ * the objects the faceset path is trying not to build. Non-zero
5519
+ * offsets still go through a vtable, because only field 0 has that
5520
+ * address identity.
5521
+ *
5522
+ * @param localID The record's local ID.
5523
+ * @param offset The field's vtable offset.
5524
+ * @param expectedTypeID The type the record must be.
5525
+ * @param sink Receives the appended values.
5526
+ * @return {number | undefined} Count appended, or undefined when the
5527
+ * fast path does not apply.
5528
+ */
5529
+ extractIntegerArrayByLocalIDInto(localID, offset, expectedTypeID, sink) {
5530
+ if (localID >= this.count_) {
5531
+ return void 0;
5532
+ }
5533
+ if (this.complexEntries_?.has(localID) || this.typeID_[localID] !== expectedTypeID) {
5534
+ return void 0;
5535
+ }
5536
+ if (offset === 0) {
5537
+ const address = this.address_[localID];
5538
+ const acquisition = this.bufferProvider_.acquire(address, this.length_[localID]);
5539
+ const viewAddress = address - acquisition.offset;
5540
+ return extractIntegerArrayAt(acquisition.buffer, viewAddress, acquisition.buffer.length, sink);
5541
+ }
5542
+ const element = this.entry(localID);
5543
+ if (element.vtableIndex === void 0 && !this.populateVtableEntryRaw(element)) {
5544
+ return void 0;
5545
+ }
5546
+ if (element.buffer === void 0) {
5547
+ this.populateBufferEntry(localID);
5548
+ }
5549
+ const vtable = element.vtable;
5550
+ const buffer = element.buffer;
5551
+ if (vtable === void 0 || buffer === void 0 || offset >= (element.vtableCount ?? 0)) {
5552
+ return void 0;
5553
+ }
5554
+ return extractIntegerArrayAt(buffer, vtable[element.vtableIndex + offset], buffer.length, sink);
5555
+ }
5556
+ /**
5557
+ * Append a referenced record's unsigned-integer list field into `sink`
5558
+ * without materialising the referenced entity.
5559
+ *
5560
+ * @param expressID The referenced record's express ID.
5561
+ * @param offset The field's vtable offset within the record.
5562
+ * @param expectedTypeID The type the record must be.
5563
+ * @param sink Receives the appended values.
5564
+ * @return {number | undefined} Count appended, or undefined when the
5565
+ * fast path does not apply.
5081
5566
  */
5567
+ extractIntegerArrayByExpressIDInto(expressID, offset, expectedTypeID, sink) {
5568
+ const localID = this.expressIDMap_.get(expressID);
5569
+ if (localID === void 0) {
5570
+ return void 0;
5571
+ }
5572
+ return this.extractIntegerArrayByLocalIDInto(localID, offset, expectedTypeID, sink);
5573
+ }
5082
5574
  populateVtableEntryRaw(element) {
5083
5575
  if (element.vtableIndex !== void 0 || element.typeID === 0) {
5084
5576
  return true;
@@ -5123,6 +5615,11 @@ var StepModelBase = class {
5123
5615
  }
5124
5616
  const element = this.entry(localID);
5125
5617
  element.buffer = this.bufferProvider_.acquire(element.address, element.length).buffer;
5618
+ if (element.multiMapping !== void 0) {
5619
+ for (const mapped of element.multiMapping) {
5620
+ mapped.buffer = this.bufferProvider_.acquire(mapped.address, mapped.length).buffer;
5621
+ }
5622
+ }
5126
5623
  }
5127
5624
  /**
5128
5625
  * Get the size in bytes of the backing buffer for this.
@@ -5150,6 +5647,74 @@ var StepModelBase = class {
5150
5647
  get residentSourceBytes() {
5151
5648
  return this.bufferProvider_.residentBytes;
5152
5649
  }
5650
+ /**
5651
+ * Column type of a record, or `undefined` if the id is unknown / untyped.
5652
+ *
5653
+ * @param localID The record.
5654
+ * @return {number | undefined} The schema type id.
5655
+ */
5656
+ typeIDOf(localID) {
5657
+ if (localID >= this.count_) {
5658
+ return;
5659
+ }
5660
+ const typeID = this.typeID_[localID];
5661
+ return typeID < 0 ? void 0 : typeID;
5662
+ }
5663
+ /**
5664
+ * Absolute source address of a record.
5665
+ *
5666
+ * @param localID The record.
5667
+ * @return {number | undefined} The address.
5668
+ */
5669
+ recordAddress(localID) {
5670
+ return localID < this.count_ ? this.address_[localID] : void 0;
5671
+ }
5672
+ /**
5673
+ * Source length of a record.
5674
+ *
5675
+ * @param localID The record.
5676
+ * @return {number | undefined} The length.
5677
+ */
5678
+ recordLength(localID) {
5679
+ return localID < this.count_ ? this.length_[localID] : void 0;
5680
+ }
5681
+ /**
5682
+ * Pin an arbitrary source span (e.g. a faceset's packed Faces[] run).
5683
+ *
5684
+ * @param address Absolute start.
5685
+ * @param length Length in bytes.
5686
+ */
5687
+ pinAddressRange(address, length) {
5688
+ if (!this.isSourceExternal) {
5689
+ return;
5690
+ }
5691
+ this.bufferProvider_.pinRange?.(address, length);
5692
+ }
5693
+ /**
5694
+ * Drop one {@link pinAddressRange} hold.
5695
+ *
5696
+ * @param address Absolute start.
5697
+ * @param length Length in bytes.
5698
+ */
5699
+ unpinAddressRange(address, length) {
5700
+ if (!this.isSourceExternal) {
5701
+ return;
5702
+ }
5703
+ this.bufferProvider_.unpinRange?.(address, length);
5704
+ }
5705
+ /**
5706
+ * Page an arbitrary source span.
5707
+ *
5708
+ * @param address Absolute start.
5709
+ * @param length Length in bytes.
5710
+ * @return {Promise<void>} Resolves when resident.
5711
+ */
5712
+ async ensureResidentRange(address, length) {
5713
+ if (!this.isSourceExternal) {
5714
+ return;
5715
+ }
5716
+ await this.bufferProvider_.ensureResident(address, length);
5717
+ }
5153
5718
  /**
5154
5719
  * Release the resident source buffer and serve subsequent record
5155
5720
  * reads from fixed-size windows paged in from an external store.
@@ -5224,6 +5789,320 @@ var StepModelBase = class {
5224
5789
  }
5225
5790
  await this.ensureResidentByLocalID(localID);
5226
5791
  }
5792
+ /**
5793
+ * Page in the byte ranges a record *and every `#ref` reachable from
5794
+ * its text* will need, so a following synchronous extract of that
5795
+ * subgraph succeeds on a windowed source. Inverse relationships
5796
+ * (not written in the record) are not discovered — callers that
5797
+ * need them (rel-voids, styled items) pass their local IDs as
5798
+ * `extraLocalIDs`.
5799
+ *
5800
+ * No-op while the source is fully resident.
5801
+ *
5802
+ * @param localID Seed record.
5803
+ * @param extraLocalIDs Additional seeds (voids, styles, materials).
5804
+ * @param seen Optional set to extend (also skips already-pinned IDs).
5805
+ * @param descend If set, records for which this returns false are
5806
+ * still visited (pinned, in `seen`) but their `#refs` are not
5807
+ * followed — e.g. an `IfcPolygonalFaceSet` whose Faces[] payload
5808
+ * is paged as one span afterwards.
5809
+ * @param leafSpans Optional out-array of coalesced pin ranges for
5810
+ * {@link spanLeaf} children — caller must {@link unpinAddressRange}
5811
+ * each.
5812
+ * @param spanLeaf If set, matching children are *not* visited
5813
+ * (absent from `seen`); their bytes are one pin span. Packed
5814
+ * extract reads `IfcIndexedPolygonalFace.CoordIndex` as integers —
5815
+ * following those faces pinned ~78k records per PSB product. If
5816
+ * omitted, `!descend` children use this span path (test helper).
5817
+ * @param claimed Optional out-set of the IDs *this call* claimed and
5818
+ * awaited residency for — a strict subset of `seen`. When `seen` is
5819
+ * shared across concurrent walks (a batch of products sharing mapped
5820
+ * geometry), an ID another walk claimed is skipped here and is NOT
5821
+ * resident yet from this call's point of view: that walk's pin holds
5822
+ * the chunk once it lands, but its read is still in flight. Anything
5823
+ * that must synchronously read a record's bytes after this returns
5824
+ * has to iterate `claimed`, never `seen` (conway#526).
5825
+ * @return {Promise<Set<number>>} The local IDs that were visited.
5826
+ */
5827
+ async ensureResidentClosureByLocalID(localID, extraLocalIDs, seen = /* @__PURE__ */ new Set(), descend, leafSpans, spanLeaf, claimed) {
5828
+ if (!this.isSourceExternal) {
5829
+ return seen;
5830
+ }
5831
+ const frontier = [];
5832
+ const enqueue = (id) => {
5833
+ if (id < this.count_ && !seen.has(id)) {
5834
+ frontier.push(id);
5835
+ }
5836
+ };
5837
+ enqueue(localID);
5838
+ if (extraLocalIDs !== void 0) {
5839
+ for (const extra of extraLocalIDs) {
5840
+ enqueue(extra);
5841
+ }
5842
+ }
5843
+ while (frontier.length > 0) {
5844
+ const wave = [];
5845
+ for (const id of frontier) {
5846
+ if (seen.has(id) || id >= this.count_) {
5847
+ continue;
5848
+ }
5849
+ seen.add(id);
5850
+ this.pinByLocalID(id);
5851
+ wave.push(id);
5852
+ claimed?.add(id);
5853
+ }
5854
+ frontier.length = 0;
5855
+ if (wave.length === 0) {
5856
+ break;
5857
+ }
5858
+ await Promise.all(wave.map((id) => this.ensureResidentByLocalID(id)));
5859
+ const waveSpans = [];
5860
+ for (const id of wave) {
5861
+ if (descend !== void 0 && !descend(id)) {
5862
+ continue;
5863
+ }
5864
+ const skipped = [];
5865
+ for (const expressID of this.scanRecordRefs_(id)) {
5866
+ const referenced = this.expressIDMap_.get(expressID);
5867
+ if (referenced === void 0 || seen.has(referenced)) {
5868
+ continue;
5869
+ }
5870
+ const leaf = spanLeaf !== void 0 ? spanLeaf(referenced) : descend !== void 0 && !descend(referenced);
5871
+ if (leaf) {
5872
+ skipped.push(referenced);
5873
+ continue;
5874
+ }
5875
+ frontier.push(referenced);
5876
+ }
5877
+ if (skipped.length > 0) {
5878
+ for (const span of this.spansOf_(skipped)) {
5879
+ this.pinAddressRange(span.address, span.length);
5880
+ waveSpans.push(span);
5881
+ leafSpans?.push(span);
5882
+ }
5883
+ }
5884
+ }
5885
+ if (waveSpans.length > 0) {
5886
+ await Promise.all(waveSpans.map((span) => this.ensureResidentRange(span.address, span.length)));
5887
+ }
5888
+ }
5889
+ return seen;
5890
+ }
5891
+ /**
5892
+ * Hold a record's source range against windowed LRU eviction until
5893
+ * {@link unpinByLocalID}. No-op while the source is fully resident.
5894
+ *
5895
+ * @param localID The record to pin.
5896
+ */
5897
+ pinByLocalID(localID) {
5898
+ if (!this.isSourceExternal || localID >= this.count_) {
5899
+ return;
5900
+ }
5901
+ this.bufferProvider_.pinRange?.(this.address_[localID], this.length_[localID]);
5902
+ }
5903
+ /**
5904
+ * Drop one {@link pinByLocalID} hold.
5905
+ *
5906
+ * @param localID The record to unpin.
5907
+ */
5908
+ unpinByLocalID(localID) {
5909
+ if (!this.isSourceExternal || localID >= this.count_) {
5910
+ return;
5911
+ }
5912
+ this.bufferProvider_.unpinRange?.(this.address_[localID], this.length_[localID]);
5913
+ }
5914
+ /**
5915
+ * Drop captured source-window views on `localIDs` so the LRU can
5916
+ * evict those chunks. Vtables stay — `acquire` of the same
5917
+ * `(address, length)` is at a stable base. The next
5918
+ * `ensureResident` + field read rematerialises the view.
5919
+ *
5920
+ * @param localIDs Records whose `buffer` views to drop.
5921
+ */
5922
+ releaseSourceViews(localIDs) {
5923
+ if (!this.isSourceExternal) {
5924
+ return;
5925
+ }
5926
+ for (const localID of localIDs) {
5927
+ if (localID >= this.count_) {
5928
+ continue;
5929
+ }
5930
+ const item = this.complexEntries_?.get(localID) ?? this.descriptorCache_[localID];
5931
+ if (item === void 0) {
5932
+ continue;
5933
+ }
5934
+ item.buffer = void 0;
5935
+ if (item.multiMapping !== void 0) {
5936
+ for (const mapped of item.multiMapping) {
5937
+ mapped.buffer = void 0;
5938
+ }
5939
+ }
5940
+ }
5941
+ releaseScratchParsingBuffer();
5942
+ }
5943
+ /**
5944
+ * Unpin every local ID in `localIDs` (best-effort; missing IDs are
5945
+ * ignored). Use after {@link ensureResidentClosureByLocalID}, which
5946
+ * pins as it walks.
5947
+ *
5948
+ * @param localIDs The records to unpin.
5949
+ */
5950
+ unpinLocalIDs(localIDs) {
5951
+ for (const localID of localIDs) {
5952
+ this.unpinByLocalID(localID);
5953
+ }
5954
+ }
5955
+ /**
5956
+ * Express-ID twin of {@link ensureResidentClosureByLocalID}. Unknown
5957
+ * IDs resolve to an empty visit set.
5958
+ *
5959
+ * @param expressID Seed record.
5960
+ * @param extraLocalIDs Additional seeds (local IDs).
5961
+ * @return {Promise<Set<number>>} The local IDs that were visited.
5962
+ */
5963
+ async ensureResidentClosureByExpressID(expressID, extraLocalIDs, seen) {
5964
+ if (!this.isSourceExternal) {
5965
+ return seen ?? /* @__PURE__ */ new Set();
5966
+ }
5967
+ const localID = this.expressIDMap_.get(expressID);
5968
+ if (localID === void 0) {
5969
+ return seen ?? /* @__PURE__ */ new Set();
5970
+ }
5971
+ return this.ensureResidentClosureByLocalID(localID, extraLocalIDs, seen);
5972
+ }
5973
+ /**
5974
+ * Source spans covering the records referenced by `expressIDs` from
5975
+ * `fromIndex` onward. A packed Faces[] run is consecutive in parse
5976
+ * order — two express-ID lookups then cover the whole range. Sparse
5977
+ * sets are coalesced into tight runs so intervening file is not
5978
+ * pinned.
5979
+ *
5980
+ * @param expressIDs Referenced express IDs (e.g. a faceset's #refs).
5981
+ * @param fromIndex First index to include (skip Coordinates at [0]).
5982
+ * @return {{address: number, length: number}[]} The spans.
5983
+ */
5984
+ spansOfExpressIDs(expressIDs, fromIndex = 0) {
5985
+ let minExpressID = Infinity;
5986
+ let maxExpressID = 0;
5987
+ let count = 0;
5988
+ for (let i = fromIndex; i < expressIDs.length; ++i) {
5989
+ const expressID = expressIDs[i];
5990
+ if (expressID < minExpressID) {
5991
+ minExpressID = expressID;
5992
+ }
5993
+ if (expressID > maxExpressID) {
5994
+ maxExpressID = expressID;
5995
+ }
5996
+ ++count;
5997
+ }
5998
+ if (count === 0 || !Number.isFinite(minExpressID)) {
5999
+ return [];
6000
+ }
6001
+ const minLocal = this.expressIDMap_.get(minExpressID);
6002
+ const maxLocal = this.expressIDMap_.get(maxExpressID);
6003
+ if (minLocal === void 0 || maxLocal === void 0) {
6004
+ return [];
6005
+ }
6006
+ const lo = Math.min(minLocal, maxLocal);
6007
+ const hi = Math.max(minLocal, maxLocal);
6008
+ if (hi - lo + 1 === count) {
6009
+ const address = this.address_[lo];
6010
+ const end = this.address_[hi] + this.length_[hi];
6011
+ if (end <= address) {
6012
+ return [];
6013
+ }
6014
+ return [{ address, length: end - address }];
6015
+ }
6016
+ const locals = [];
6017
+ for (let i = fromIndex; i < expressIDs.length; ++i) {
6018
+ const localID = this.expressIDMap_.get(expressIDs[i]);
6019
+ if (localID !== void 0) {
6020
+ locals.push(localID);
6021
+ }
6022
+ }
6023
+ return this.spansOf_(locals);
6024
+ }
6025
+ /**
6026
+ * Coalesce `localIDs` into tight source runs. Records more than
6027
+ * {@link LEAF_SPAN_COALESCE_GAP_} apart stay separate so a sparse
6028
+ * Faces[] list does not pin the file between them.
6029
+ *
6030
+ * @param localIDs The records.
6031
+ * @return {{address: number, length: number}[]} The spans.
6032
+ */
6033
+ spansOf_(localIDs) {
6034
+ const items = [];
6035
+ for (const id of localIDs) {
6036
+ if (id >= this.count_) {
6037
+ continue;
6038
+ }
6039
+ items.push({
6040
+ address: this.address_[id],
6041
+ length: this.length_[id]
6042
+ });
6043
+ }
6044
+ items.sort((a2, b) => a2.address - b.address);
6045
+ const spans = [];
6046
+ let run;
6047
+ for (const item of items) {
6048
+ if (run === void 0) {
6049
+ run = { address: item.address, length: item.length };
6050
+ continue;
6051
+ }
6052
+ const runEnd = run.address + run.length;
6053
+ if (item.address <= runEnd + _StepModelBase.LEAF_SPAN_COALESCE_GAP_) {
6054
+ const end = Math.max(runEnd, item.address + item.length);
6055
+ run.length = end - run.address;
6056
+ continue;
6057
+ }
6058
+ spans.push(run);
6059
+ run = { address: item.address, length: item.length };
6060
+ }
6061
+ if (run !== void 0) {
6062
+ spans.push(run);
6063
+ }
6064
+ return spans;
6065
+ }
6066
+ /**
6067
+ * Express IDs referenced by a resident record (`#<id>` tokens in its
6068
+ * text, including multi-mapped class records). The record itself
6069
+ * must already be resident.
6070
+ *
6071
+ * @param localID The record to scan.
6072
+ * @return {number[]} Distinct referenced express IDs.
6073
+ */
6074
+ referencedExpressIDs(localID) {
6075
+ return this.scanRecordRefs_(localID);
6076
+ }
6077
+ /**
6078
+ * Scan a resident record's bytes for `#<expressID>` references.
6079
+ *
6080
+ * @param localID The record to scan.
6081
+ * @return {number[]} Distinct referenced express IDs.
6082
+ */
6083
+ scanRecordRefs_(localID) {
6084
+ const address = this.address_[localID];
6085
+ const length = this.length_[localID];
6086
+ const acquisition = this.bufferProvider_.acquire(address, length);
6087
+ const viewStart = address - acquisition.offset;
6088
+ const refs = scanExpressRefs(acquisition.buffer, viewStart, length);
6089
+ const complex = this.complexEntries_?.get(localID);
6090
+ if (complex?.multiMapping === void 0) {
6091
+ return refs;
6092
+ }
6093
+ const seen = new Set(refs);
6094
+ for (const mapped of complex.multiMapping) {
6095
+ const mappedAcquisition = this.bufferProvider_.acquire(mapped.address, mapped.length);
6096
+ const mappedStart = mapped.address - mappedAcquisition.offset;
6097
+ for (const expressID of scanExpressRefs(mappedAcquisition.buffer, mappedStart, mapped.length)) {
6098
+ if (!seen.has(expressID)) {
6099
+ seen.add(expressID);
6100
+ refs.push(expressID);
6101
+ }
6102
+ }
6103
+ }
6104
+ return refs;
6105
+ }
5227
6106
  /**
5228
6107
  * Get the number of elements/entities in this model.
5229
6108
  *
@@ -5608,6 +6487,8 @@ var StepModelBase = class {
5608
6487
  return this.geometry?.getByLocalID(node.localID);
5609
6488
  }
5610
6489
  };
6490
+ StepModelBase.LEAF_SPAN_COALESCE_GAP_ = 1024;
6491
+ var step_model_base_default = StepModelBase;
5611
6492
 
5612
6493
  // compiled/src/core/entity_field_description.js
5613
6494
  var FieldDescriptionKind;
@@ -10195,6 +11076,67 @@ function IfcWorkScheduleTypeEnumDeserializeStep(input2, cursor, endCursor) {
10195
11076
  return parser208.extract(IfcWorkScheduleTypeEnumSearch, input2, cursor, endCursor);
10196
11077
  }
10197
11078
 
11079
+ // compiled/src/core/wasm_heap.js
11080
+ function describeHeap(wasmModule, arrayPtr, numBytes) {
11081
+ const heap = wasmModule.HEAPU8;
11082
+ const buffer = currentHeapBuffer(wasmModule);
11083
+ const shared = typeof SharedArrayBuffer !== "undefined" && buffer instanceof SharedArrayBuffer;
11084
+ const kind = buffer === void 0 ? "none" : shared ? "SharedArrayBuffer" : "ArrayBuffer";
11085
+ const extensible = shared ? buffer?.growable : buffer?.resizable;
11086
+ return `ptr ${arrayPtr} + ${numBytes} bytes, heap view length ${heap?.length}, buffer ${kind} byteLength ${buffer?.byteLength}, extensible ${extensible}`;
11087
+ }
11088
+ function currentHeapBuffer(wasmModule) {
11089
+ const memory = wasmModule.wasmMemory;
11090
+ return memory !== void 0 ? memory.buffer : wasmModule.HEAPU8?.buffer;
11091
+ }
11092
+ function refreshHeapViews(wasmModule) {
11093
+ if (typeof wasmModule.updateMemoryViews === "function") {
11094
+ wasmModule.updateMemoryViews();
11095
+ return;
11096
+ }
11097
+ if (wasmModule.wasmMemory !== void 0) {
11098
+ return;
11099
+ }
11100
+ const StringVector = wasmModule.stringVector;
11101
+ if (StringVector === void 0) {
11102
+ return;
11103
+ }
11104
+ let scratch;
11105
+ releaseQuietly(() => {
11106
+ const created2 = new StringVector();
11107
+ scratch = created2;
11108
+ created2.push_back("");
11109
+ });
11110
+ const created = scratch;
11111
+ if (created !== void 0) {
11112
+ releaseQuietly(() => created.delete());
11113
+ }
11114
+ }
11115
+ function reconcileHeapBuffer(wasmModule, address, numBytes) {
11116
+ const buffer = currentHeapBuffer(wasmModule);
11117
+ if (buffer !== void 0 && address + numBytes <= buffer.byteLength) {
11118
+ return buffer;
11119
+ }
11120
+ refreshHeapViews(wasmModule);
11121
+ const refreshed = currentHeapBuffer(wasmModule);
11122
+ if (refreshed !== void 0 && address + numBytes <= refreshed.byteLength) {
11123
+ return refreshed;
11124
+ }
11125
+ throw new Error("wasm heap allocation lies outside the heap, and refreshing the module views did not reconcile it. " + describeHeap(wasmModule, address, numBytes));
11126
+ }
11127
+ function wasmHeapView(wasmModule, arrayType, pointer, elementCount) {
11128
+ const address = pointer >>> 0;
11129
+ const numBytes = elementCount * arrayType.BYTES_PER_ELEMENT;
11130
+ return new arrayType(reconcileHeapBuffer(wasmModule, address, numBytes), address, elementCount);
11131
+ }
11132
+ function releaseQuietly(release) {
11133
+ try {
11134
+ release();
11135
+ } catch (error) {
11136
+ logger_default.debug(`wasm resource release failed during teardown: ${error instanceof Error ? error.message : error}`);
11137
+ }
11138
+ }
11139
+
10198
11140
  // compiled/src/step/step_entity_base.js
10199
11141
  var IfcTokenType;
10200
11142
  (function(IfcTokenType2) {
@@ -10351,6 +11293,27 @@ var StepEntityBase = class {
10351
11293
  }
10352
11294
  return value;
10353
11295
  }
11296
+ /**
11297
+ * Extract a number at the particular vtable offset (i.e. the position
11298
+ * in the matching step object).
11299
+ *
11300
+ * Used by other extraction methods with wrappers to perform
11301
+ * semantically correct extraction.
11302
+ *
11303
+ * Unlike the other extractors this has a single signature rather than an
11304
+ * optional/non-optional overload pair, because LOGICAL is three-valued:
11305
+ * `.U.` is a legitimate value that reads as null, so a non-optional LOGICAL
11306
+ * is null-valued too and `optional` only decides whether a *missing* value
11307
+ * throws. The old `optional: false` overload promised a bare `boolean` and
11308
+ * was a lie for exactly the `.U.` case this extractor exists to handle.
11309
+ *
11310
+ * @param offset The offset in the vtable to extract from
11311
+ * @param baseOffset The base offset in the vtable to extract from
11312
+ * @param depth The depth of the vtable to extract from
11313
+ * @param optional Is this an optional field?
11314
+ * @return {boolean | null} The extracted logical, or null for `.U.` and for
11315
+ * an absent optional.
11316
+ */
10354
11317
  extractLogical(offset, baseOffset, depth, optional) {
10355
11318
  const [cursor, endCursor, buffer] = this.getOffsetAndEndCursor(offset, baseOffset, depth);
10356
11319
  const value = stepExtractLogical(buffer, cursor, endCursor);
@@ -10380,6 +11343,38 @@ var StepEntityBase = class {
10380
11343
  }
10381
11344
  return value;
10382
11345
  }
11346
+ /**
11347
+ * Resolve a single reference field to its local ID without
11348
+ * constructing the target entity. Prep maps that only store
11349
+ * `Item.localID` (IfcStyledItem → faceset) must not hydrate the
11350
+ * target: on a windowed source that would pin the faceset record
11351
+ * (often megabytes) for every styled item at once.
11352
+ *
11353
+ * @param offset The offset in the vtable to extract from.
11354
+ * @param baseOffset The base offset of the class in the vtable.
11355
+ * @param depth The depth in the inheritance hierarchy.
11356
+ * @param optional Is this an optional field?
11357
+ * @return {number | null} The referenced local ID, or null if the
11358
+ * field is unset/optional-null.
11359
+ */
11360
+ extractReferenceLocalID(offset, baseOffset, depth, optional) {
11361
+ const [cursor, endCursor, buffer] = this.getOffsetAndEndCursor(offset, baseOffset, depth);
11362
+ const expressID = stepExtractReference(buffer, cursor, endCursor);
11363
+ if (expressID !== void 0) {
11364
+ return this.model.resolveExpressID(expressID) ?? null;
11365
+ }
11366
+ const inline = this.model.getInlineElementByAddress(extractInlineElementAddress(buffer, cursor, endCursor));
11367
+ if (inline !== void 0) {
11368
+ return inline.localID;
11369
+ }
11370
+ if (!optional) {
11371
+ throw new Error("Value in STEP was incorrectly typed");
11372
+ }
11373
+ if (!this.model.nullOnErrors && stepExtractOptional(buffer, cursor, endCursor) !== null) {
11374
+ throw new Error("Value in STEP was incorrectly typed");
11375
+ }
11376
+ return null;
11377
+ }
10383
11378
  /**
10384
11379
  *
10385
11380
  * @param buffer
@@ -10585,6 +11580,7 @@ var StepEntityBase = class {
10585
11580
  */
10586
11581
  extractParseBuffer(offset, baseOffset, depth, result, module2, optional) {
10587
11582
  offset -= this.multiReference_ !== void 0 ? baseOffset : 0;
11583
+ this.guaranteeBuffer();
10588
11584
  const internalReference = this.guaranteeVTable(depth);
10589
11585
  if (offset >= internalReference.vtableCount) {
10590
11586
  throw new Error("Couldn't read field due to too few fields in record");
@@ -10597,10 +11593,72 @@ var StepEntityBase = class {
10597
11593
  if (optional && stepExtractOptional(buffer, cursor, endCursor) === null) {
10598
11594
  return false;
10599
11595
  }
10600
- const dataPtr = result.resize(endCursor - cursor);
10601
- module2.HEAPU8.set(buffer.subarray(cursor, endCursor), dataPtr);
11596
+ const length = endCursor - cursor;
11597
+ const dataPtr = result.resize(length);
11598
+ wasmHeapView(module2, Uint8Array, dataPtr, length).set(buffer.subarray(cursor, endCursor));
10602
11599
  return true;
10603
11600
  }
11601
+ /**
11602
+ * Append an unsigned-integer list field straight from the STEP buffer
11603
+ * into `sink`, without materialising an intermediate `Array< number >`.
11604
+ *
11605
+ * Semantically identical to the generated array getters (same
11606
+ * optional handling, same element extraction, same "incorrectly
11607
+ * typed" error), but it neither allocates nor caches a per-record
11608
+ * array — the caller owns one reusable sink for the whole batch. On
11609
+ * tessellated models this removes millions of short-lived arrays and
11610
+ * the retained heap that goes with them; see Uint32Sink.
11611
+ *
11612
+ * @param offset The offset in the vtable to extract from.
11613
+ * @param baseOffset The base offset of the class in the vtable.
11614
+ * @param depth The depth in the inheritance hierarchy.
11615
+ * @param sink Receives the appended values.
11616
+ * @return {number} How many values were appended (0 when the field is
11617
+ * unset/optional-null).
11618
+ */
11619
+ /**
11620
+ * Walk a reference-list field, handing each element's express ID to
11621
+ * `onReference` without resolving it to an entity.
11622
+ *
11623
+ * Lets hot loops decide per element how to read the referenced record
11624
+ * (see StepModelBase.extractIntegerArrayByExpressIDInto) instead of
11625
+ * paying for an entity per element the way the generated list getters
11626
+ * do. Inline (non-reference) elements yield `undefined`, and
11627
+ * `onReference` returning false aborts the walk — together those let
11628
+ * a caller bail out to the generated getter for anything it is not
11629
+ * prepared to handle.
11630
+ *
11631
+ * @param offset The offset in the vtable to extract from.
11632
+ * @param baseOffset The base offset of the class in the vtable.
11633
+ * @param depth The depth in the inheritance hierarchy.
11634
+ * @param onReference Receives each element's express ID, or undefined
11635
+ * for an inline element; return false to abort.
11636
+ * @return {boolean} False if the walk was aborted, true otherwise.
11637
+ */
11638
+ forEachReferenceInField(offset, baseOffset, depth, onReference) {
11639
+ let cursor = this.getOffsetCursor(offset, baseOffset, depth);
11640
+ const buffer = this.buffer;
11641
+ const endCursor = buffer.length;
11642
+ if (stepExtractOptional(buffer, cursor, endCursor) === null) {
11643
+ return true;
11644
+ }
11645
+ let signedCursor0 = stepExtractArrayBegin(buffer, cursor, endCursor);
11646
+ cursor = Math.abs(signedCursor0);
11647
+ while (signedCursor0 >= 0) {
11648
+ if (!onReference(stepExtractReference(buffer, cursor, endCursor))) {
11649
+ return false;
11650
+ }
11651
+ cursor = skipValue(buffer, cursor, endCursor);
11652
+ signedCursor0 = stepExtractArrayToken(buffer, cursor, endCursor);
11653
+ cursor = Math.abs(signedCursor0);
11654
+ }
11655
+ return true;
11656
+ }
11657
+ extractIntegerArrayInto(offset, baseOffset, depth, sink) {
11658
+ const cursor = this.getOffsetCursor(offset, baseOffset, depth);
11659
+ const buffer = this.buffer;
11660
+ return extractIntegerArrayAt(buffer, cursor, buffer.length, sink);
11661
+ }
10604
11662
  /**
10605
11663
  * Extract a number at the particular vtable offset (i.e. the position
10606
11664
  * in the matching step object).
@@ -10636,6 +11694,7 @@ var StepEntityBase = class {
10636
11694
  * @return {Uint8Array} The buffer for this.
10637
11695
  */
10638
11696
  get buffer() {
11697
+ this.guaranteeBuffer();
10639
11698
  return this.internalReference_.buffer;
10640
11699
  }
10641
11700
  /**
@@ -10726,6 +11785,9 @@ var StepEntityBase = class {
10726
11785
  throw new Error("Entity does not have matching table entry to read from model");
10727
11786
  }
10728
11787
  }
11788
+ if (classReference.buffer === void 0) {
11789
+ this.model.populateBufferEntry(this.localID);
11790
+ }
10729
11791
  this.internalReference_.buffer = classReference.buffer;
10730
11792
  return classReference;
10731
11793
  }
@@ -10736,6 +11798,9 @@ var StepEntityBase = class {
10736
11798
  throw new Error("Entity does not have matching table entry to read from model");
10737
11799
  }
10738
11800
  }
11801
+ if (internalReference.buffer === void 0) {
11802
+ this.guaranteeBuffer();
11803
+ }
10739
11804
  return internalReference;
10740
11805
  }
10741
11806
  /**
@@ -12562,7 +13627,7 @@ var IfcPresentationStyleAssignment = class extends StepEntityBase {
12562
13627
  let signedCursor0 = stepExtractArrayBegin(buffer, cursor, endCursor);
12563
13628
  cursor = Math.abs(signedCursor0);
12564
13629
  while (signedCursor0 >= 0) {
12565
- const value1Untyped = this.extractBufferReference(buffer, cursor, endCursor) ?? IfcNullStyleDeserializeStep(buffer, cursor, endCursor);
13630
+ const value1Untyped = this.extractBufferReference(buffer, cursor, endCursor) ?? IfcNullStyleDeserializeStep(buffer, stepEnterTypedValue(buffer, cursor, endCursor, "IFCNULLSTYLE"), endCursor);
12566
13631
  if (!(value1Untyped instanceof IfcCurveStyle) && !(value1Untyped instanceof IfcFillAreaStyle) && !(value1Untyped instanceof IfcSurfaceStyle) && !(value1Untyped instanceof IfcTextStyle) && value1Untyped !== IfcNullStyle.NULL) {
12567
13632
  throw new Error("Value in select must be populated");
12568
13633
  }
@@ -14390,7 +15455,7 @@ var IfcLogical = class extends StepEntityBase {
14390
15455
  }
14391
15456
  get Value() {
14392
15457
  if (this.Value_ === void 0) {
14393
- this.Value_ = this.extractBoolean(0, 0, 0, false);
15458
+ this.Value_ = this.extractLogical(0, 0, 0, false);
14394
15459
  }
14395
15460
  return this.Value_;
14396
15461
  }
@@ -25512,7 +26577,7 @@ var IfcRelInterferesElements = class extends IfcRelConnects {
25512
26577
  }
25513
26578
  get ImpliedOrder() {
25514
26579
  if (this.ImpliedOrder_ === void 0) {
25515
- this.ImpliedOrder_ = this.extractBoolean(8, 4, 3, false);
26580
+ this.ImpliedOrder_ = this.extractLogical(8, 4, 3, false);
25516
26581
  }
25517
26582
  return this.ImpliedOrder_;
25518
26583
  }
@@ -63780,7 +64845,7 @@ var descriptions = [
63780
64845
  },
63781
64846
  ImpliedOrder: {
63782
64847
  kind: f.BOOLEAN,
63783
- optional: false,
64848
+ optional: true,
63784
64849
  derived: false,
63785
64850
  offset: 8
63786
64851
  }
@@ -68752,7 +69817,7 @@ var descriptions = [
68752
69817
  fields: {
68753
69818
  Value: {
68754
69819
  kind: f.BOOLEAN,
68755
- optional: false,
69820
+ optional: true,
68756
69821
  derived: false,
68757
69822
  offset: 0
68758
69823
  }
@@ -70049,6 +71114,68 @@ var StepTypeIndexer = class {
70049
71114
  constructor(typeCount) {
70050
71115
  this.elementCounter_ = new Int32Array(typeCount << 1);
70051
71116
  }
71117
+ /**
71118
+ * Create a type index from either index form — the parsed object array or
71119
+ * the columnar index (M7).
71120
+ *
71121
+ * @param index The element index, object or columnar.
71122
+ * @return {MultiIndexSet} The created multi-set index.
71123
+ */
71124
+ createFor(index) {
71125
+ return Array.isArray(index) ? this.create(index) : this.createFromColumns(index);
71126
+ }
71127
+ /**
71128
+ * Create a type index straight from the columnar index — the same
71129
+ * membership `create` produces from the unfolded object array: every row's
71130
+ * concrete type (top-level + inline; −1 rows skipped) plus the
71131
+ * multi-mapping subtypes of retained complex entries at their parent's
71132
+ * dense index.
71133
+ *
71134
+ * @param columns The columnar index.
71135
+ * @return {MultiIndexSet} The created multi-set index.
71136
+ */
71137
+ createFromColumns(columns) {
71138
+ for (let where = 0, end = this.elementCounter_.length; where < end; where += 2) {
71139
+ initCountCompactedElements32State(this.elementCounter_, where);
71140
+ }
71141
+ const elementCounter = this.elementCounter_;
71142
+ const prefixSum = new Uint32Array((this.elementCounter_.length >>> 1) + 1);
71143
+ const typeIDs = columns.typeID;
71144
+ const count = columns.count;
71145
+ const walkRows = (addOne) => {
71146
+ const complexIterator = columns.complexEntries?.entries();
71147
+ let nextComplex = complexIterator?.next();
71148
+ for (let denseIndex = 0; denseIndex < count; ++denseIndex) {
71149
+ const typeID = typeIDs[denseIndex];
71150
+ if (typeID >= 0) {
71151
+ addOne(denseIndex, typeID);
71152
+ }
71153
+ if (nextComplex !== void 0 && !nextComplex.done && nextComplex.value[0] === denseIndex) {
71154
+ for (const subElement of nextComplex.value[1].multiMapping ?? []) {
71155
+ const subTypeID = subElement.typeID;
71156
+ if (subTypeID !== void 0) {
71157
+ addOne(denseIndex, subTypeID);
71158
+ }
71159
+ }
71160
+ nextComplex = complexIterator.next();
71161
+ }
71162
+ }
71163
+ };
71164
+ walkRows((denseIndex, typeID) => {
71165
+ prefixSum[typeID + 1] = addCompactedElementCount32State(denseIndex, elementCounter, typeID << 1);
71166
+ });
71167
+ for (let prefixSumIndex = 2, prefixSumEnd = prefixSum.length; prefixSumIndex < prefixSumEnd; ++prefixSumIndex) {
71168
+ prefixSum[prefixSumIndex] += prefixSum[prefixSumIndex - 1];
71169
+ }
71170
+ for (let where = 0, end = this.elementCounter_.length; where < end; where += 2) {
71171
+ initCountCompactedElements32State(this.elementCounter_, where);
71172
+ }
71173
+ const indexOutput = new Uint32Array(prefixSum[prefixSum.length - 1] << 1);
71174
+ walkRows((denseIndex, typeID) => {
71175
+ addCompactedElement32State(denseIndex, elementCounter, indexOutput, typeID << 1, prefixSum[typeID] << 1);
71176
+ });
71177
+ return new MultiIndexSet(prefixSum, indexOutput);
71178
+ }
70052
71179
  /**
70053
71180
  * Create a type index from a set of parsed STEP elements.
70054
71181
  *
@@ -70216,9 +71343,24 @@ var IfcModelGeometry = class {
70216
71343
  /**
70217
71344
  * Add a mesh to the geometry cache.
70218
71345
  *
71346
+ * Freezes the native float vertex mirror at add time (one
71347
+ * GetVertexData call): consumers (the compat GetGeometry surface)
71348
+ * read float vertices whose frame must match the scene transforms,
71349
+ * which are authored against the geometry AS CREATED. Later native
71350
+ * mutations that keep the vertex count (normalize's centering)
71351
+ * deliberately do NOT refresh the mirror, so every extraction path —
71352
+ * whole-model walk, per-product demand pump, parse-time preview —
71353
+ * serves the same creation-frame floats. Without this, paths that
71354
+ * first read vertices only after a centering mutation serve
71355
+ * per-geometry-shifted vertices against unshifted transforms
71356
+ * (Share's demand-path "scatter").
71357
+ *
70219
71358
  * @param mesh
70220
71359
  */
70221
71360
  add(mesh) {
71361
+ if (mesh.type === CanonicalMeshType.BUFFER_GEOMETRY) {
71362
+ mesh.geometry.GetVertexData();
71363
+ }
70222
71364
  this.meshes_.set(mesh.localID, mesh);
70223
71365
  }
70224
71366
  /**
@@ -70689,16 +71831,18 @@ var IfcMaterialCache = class {
70689
71831
 
70690
71832
  // compiled/src/ifc/ifc_step_model.js
70691
71833
  var indexerInstance = new StepTypeIndexer(EntityTypesIfcCount);
70692
- var IfcStepModel = class extends StepModelBase {
71834
+ var IfcStepModel = class extends step_model_base_default {
70693
71835
  /**
70694
71836
  * Construct this model given a buffer containing the data and the parsed data index on that,
70695
71837
  * adding the typeIndex on top of that.
70696
71838
  *
70697
- * @param buffer The buffer to values from.
71839
+ * @param buffer The buffer to values from, or `undefined` with `provider`
71840
+ * set for a windowed (streaming) source.
70698
71841
  * @param elementIndex The parsed index to elements in the STEP.
71842
+ * @param provider Optional pre-built buffer provider (windowed source).
70699
71843
  */
70700
- constructor(buffer, elementIndex) {
70701
- super(schema_ifc_gen_default, buffer, elementIndex);
71844
+ constructor(buffer, elementIndex, provider) {
71845
+ super(schema_ifc_gen_default, buffer, elementIndex, provider);
70702
71846
  this.externalMappingType = ifc_step_external_mapping_default;
70703
71847
  this.geometry = new IfcModelGeometry(this);
70704
71848
  this.voidGeometry = new IfcModelGeometry(this, true);
@@ -70708,11 +71852,330 @@ var IfcStepModel = class extends StepModelBase {
70708
71852
  this.materials = new IfcMaterialCache(this);
70709
71853
  this.voidMaterials = new IfcMaterialCache(this, true);
70710
71854
  this.elementTypeIDs = entity_types_ifc_gen_default;
70711
- this.typeIndex = indexerInstance.create(elementIndex);
71855
+ this.typeIndex = indexerInstance.createFor(elementIndex);
70712
71856
  }
70713
71857
  };
70714
71858
 
71859
+ // compiled/src/step/parsing/columnar_index.js
71860
+ var COLUMN_UNDEFINED_TYPE = -1;
71861
+ var SEGMENT_ROWS = 64 * 1024;
71862
+ var ColumnarIndexSink = class {
71863
+ constructor() {
71864
+ this.segments_ = [];
71865
+ this.count_ = 0;
71866
+ this.retained_ = /* @__PURE__ */ new Map();
71867
+ this.expressIdsSorted_ = true;
71868
+ this.previousExpressID_ = 0;
71869
+ }
71870
+ /**
71871
+ * @return {number} Top-level records pushed so far.
71872
+ */
71873
+ get topLevelCount() {
71874
+ return this.count_;
71875
+ }
71876
+ /**
71877
+ * Encode one completed top-level record into the columns. The entry object
71878
+ * is not kept unless it carries children (inline entities / multi-mapping).
71879
+ *
71880
+ * @param entry The completed top-level index entry.
71881
+ */
71882
+ pushTopLevel(entry) {
71883
+ const localID = this.count_++;
71884
+ const segmentIndex = Math.floor(localID / SEGMENT_ROWS);
71885
+ const row = localID % SEGMENT_ROWS;
71886
+ if (segmentIndex === this.segments_.length) {
71887
+ this.segments_.push({
71888
+ address: new Uint32Array(SEGMENT_ROWS),
71889
+ length: new Uint32Array(SEGMENT_ROWS),
71890
+ typeID: new Int32Array(SEGMENT_ROWS),
71891
+ expressID: new Uint32Array(SEGMENT_ROWS)
71892
+ });
71893
+ }
71894
+ const segment = this.segments_[segmentIndex];
71895
+ segment.address[row] = entry.address;
71896
+ segment.length[row] = entry.length;
71897
+ segment.typeID[row] = entry.typeID === void 0 ? COLUMN_UNDEFINED_TYPE : entry.typeID;
71898
+ segment.expressID[row] = entry.expressID;
71899
+ if (entry.expressID < this.previousExpressID_) {
71900
+ this.expressIdsSorted_ = false;
71901
+ }
71902
+ this.previousExpressID_ = entry.expressID;
71903
+ if (entry.inlineEntities !== void 0 || entry.multiMapping !== void 0) {
71904
+ this.retained_.set(localID, entry);
71905
+ }
71906
+ }
71907
+ /**
71908
+ * Rewind to empty (the streaming builder's grow-and-restart). The first
71909
+ * segment is kept for reuse.
71910
+ */
71911
+ reset() {
71912
+ this.segments_.length = Math.min(this.segments_.length, 1);
71913
+ this.count_ = 0;
71914
+ this.retained_.clear();
71915
+ this.expressIdsSorted_ = true;
71916
+ this.previousExpressID_ = 0;
71917
+ }
71918
+ /**
71919
+ * Snapshot the columns pushed SO FAR into a self-contained prefix index,
71920
+ * without disturbing the sink — the parse can keep pushing afterwards and
71921
+ * a later snapshot/finalize sees the full data. Safe to call between the
71922
+ * cooperative parse's yields (the parser only suspends at top-level
71923
+ * record boundaries, where the sink is consistent). Top-level localIDs
71924
+ * are stable across snapshots (dense parse order), so consumers can carry
71925
+ * per-localID cursors from one snapshot to the next; inline-range
71926
+ * localIDs are NOT stable (the inline tail re-packs after the growing
71927
+ * top-level range) and must not be carried across snapshots.
71928
+ *
71929
+ * @return {StepIndexColumns} A prefix columnar index over the records
71930
+ * pushed so far.
71931
+ */
71932
+ snapshot() {
71933
+ return this.assemble_();
71934
+ }
71935
+ /**
71936
+ * Assemble the final columns: concatenate the top-level segments (one
71937
+ * column at a time, bounding transient overhead to a single column's
71938
+ * segments) and unfold retained inline entities into the inline range in
71939
+ * the model's exact unfold order.
71940
+ *
71941
+ * @return {StepIndexColumns} The finished columnar index.
71942
+ */
71943
+ finalize() {
71944
+ return this.assemble_();
71945
+ }
71946
+ /**
71947
+ * Shared assembly behind {@link snapshot} and {@link finalize} — pure
71948
+ * over the sink's current state.
71949
+ *
71950
+ * @return {StepIndexColumns} The assembled columnar index.
71951
+ */
71952
+ assemble_() {
71953
+ const topLevel = this.count_;
71954
+ const unfolded = [];
71955
+ for (const entry of this.retained_.values()) {
71956
+ if (entry.inlineEntities !== void 0) {
71957
+ unfolded.push(...entry.inlineEntities);
71958
+ }
71959
+ }
71960
+ for (let where = 0; where < unfolded.length; ++where) {
71961
+ const inlineEntities = unfolded[where].inlineEntities;
71962
+ if (inlineEntities !== void 0) {
71963
+ unfolded.push(...inlineEntities);
71964
+ }
71965
+ }
71966
+ const count = topLevel + unfolded.length;
71967
+ const address = concatColumn(this.segments_, "address", topLevel, count);
71968
+ const length = concatColumn(this.segments_, "length", topLevel, count);
71969
+ const typeID = new Int32Array(count);
71970
+ for (let segment = 0; segment * SEGMENT_ROWS < topLevel; ++segment) {
71971
+ const rows = Math.min(SEGMENT_ROWS, topLevel - segment * SEGMENT_ROWS);
71972
+ typeID.set(this.segments_[segment].typeID.subarray(0, rows), segment * SEGMENT_ROWS);
71973
+ }
71974
+ const expressID = concatColumn(this.segments_, "expressID", topLevel, topLevel);
71975
+ for (let where = 0; where < unfolded.length; ++where) {
71976
+ const entry = unfolded[where];
71977
+ const row = topLevel + where;
71978
+ address[row] = entry.address;
71979
+ length[row] = entry.length;
71980
+ typeID[row] = entry.typeID === void 0 ? COLUMN_UNDEFINED_TYPE : entry.typeID;
71981
+ }
71982
+ let complexEntries;
71983
+ for (const [localID, entry] of this.retained_) {
71984
+ if (entry.multiMapping !== void 0) {
71985
+ (complexEntries ??= /* @__PURE__ */ new Map()).set(localID, cloneIndexEntry(entry));
71986
+ }
71987
+ }
71988
+ return {
71989
+ address,
71990
+ length,
71991
+ typeID,
71992
+ expressID,
71993
+ count,
71994
+ firstInlineElement: topLevel,
71995
+ complexEntries,
71996
+ expressIdsSorted: this.expressIdsSorted_
71997
+ };
71998
+ }
71999
+ };
72000
+ function cloneIndexEntry(entry) {
72001
+ const clone = {
72002
+ address: entry.address,
72003
+ length: entry.length
72004
+ };
72005
+ if (entry.typeID !== void 0) {
72006
+ clone.typeID = entry.typeID;
72007
+ }
72008
+ if (entry.expressID !== void 0) {
72009
+ clone.expressID = entry.expressID;
72010
+ }
72011
+ if (entry.inlineEntities !== void 0) {
72012
+ clone.inlineEntities = entry.inlineEntities;
72013
+ }
72014
+ if (entry.multiMapping !== void 0) {
72015
+ clone.multiMapping = entry.multiMapping.map(cloneIndexEntry);
72016
+ }
72017
+ return clone;
72018
+ }
72019
+ function concatColumn(segments, column, rows, finalLength) {
72020
+ const result = new Uint32Array(finalLength);
72021
+ for (let segment = 0; segment * SEGMENT_ROWS < rows; ++segment) {
72022
+ const valid = Math.min(SEGMENT_ROWS, rows - segment * SEGMENT_ROWS);
72023
+ result.set(segments[segment][column].subarray(0, valid), segment * SEGMENT_ROWS);
72024
+ }
72025
+ return result;
72026
+ }
72027
+
72028
+ // compiled/src/step/parsing/streaming_index_builder.js
72029
+ function buildIndexStreaming(source, parser211, pool3, onRecordIndexed, sink) {
72030
+ const fileSize = source.byteLength;
72031
+ let windowBytes = Math.max(pool3, MIN_WINDOW);
72032
+ for (; ; ) {
72033
+ const window2 = new Uint8Array(windowBytes);
72034
+ let windowStartFile = 0;
72035
+ let windowLen = source.read(0, windowBytes, window2, 0);
72036
+ let bytesRead = windowLen;
72037
+ const input2 = new ParsingBuffer(window2, 0, windowLen);
72038
+ const [header, headerResult] = parser211.parseHeader(input2);
72039
+ if (headerResult !== ParseResult.COMPLETE) {
72040
+ return {
72041
+ header,
72042
+ elements: [],
72043
+ result: headerResult,
72044
+ stats: { pool: pool3, windowBytes, slides: 0, maxRecordLen: 0, bytesRead }
72045
+ };
72046
+ }
72047
+ const slideThreshold = windowBytes >> 1;
72048
+ let slides = 0;
72049
+ let maxRecordLen = 0;
72050
+ let prevBoundaryFile = windowStartFile + input2.cursor;
72051
+ const onRecordBoundary = (buffer) => {
72052
+ const cursor = buffer.cursor;
72053
+ const recordFileStart = windowStartFile + cursor;
72054
+ const recordLen = recordFileStart - prevBoundaryFile;
72055
+ if (recordLen > maxRecordLen) {
72056
+ maxRecordLen = recordLen;
72057
+ }
72058
+ prevBoundaryFile = recordFileStart;
72059
+ if (windowStartFile + windowLen >= fileSize) {
72060
+ return;
72061
+ }
72062
+ if (cursor < slideThreshold) {
72063
+ return;
72064
+ }
72065
+ const tail = windowLen - cursor;
72066
+ window2.copyWithin(0, cursor, windowLen);
72067
+ const want = windowBytes - tail;
72068
+ const got = source.read(windowStartFile + windowLen, want, window2, tail);
72069
+ bytesRead += got;
72070
+ windowLen = tail + got;
72071
+ windowStartFile = recordFileStart;
72072
+ buffer.rebaseWindow(window2, 0, windowLen, windowStartFile);
72073
+ ++slides;
72074
+ };
72075
+ const [index, result] = parser211.parseDataBlockStreamed(input2, onRecordBoundary, onRecordIndexed, void 0, sink);
72076
+ const stoppedShort = result !== ParseResult.COMPLETE;
72077
+ const notAtEof = windowStartFile + windowLen < fileSize;
72078
+ if (stoppedShort && notAtEof) {
72079
+ windowBytes *= 2;
72080
+ sink?.reset();
72081
+ continue;
72082
+ }
72083
+ const lastRecordLen = windowStartFile + input2.cursor - prevBoundaryFile;
72084
+ if (lastRecordLen > maxRecordLen) {
72085
+ maxRecordLen = lastRecordLen;
72086
+ }
72087
+ return {
72088
+ header,
72089
+ elements: index.elements,
72090
+ result,
72091
+ stats: { pool: pool3, windowBytes, slides, maxRecordLen, bytesRead }
72092
+ };
72093
+ }
72094
+ }
72095
+ var MIN_WINDOW = 4 * 1024;
72096
+ async function readSource(source, offset, length, into, intoOffset) {
72097
+ return await source.read(offset, length, into, intoOffset);
72098
+ }
72099
+ async function buildIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, sink, onProgress, yieldIntervalMs) {
72100
+ const fileSize = source.byteLength;
72101
+ let windowBytes = Math.max(pool3, MIN_WINDOW);
72102
+ for (; ; ) {
72103
+ const window2 = new Uint8Array(windowBytes);
72104
+ let windowStartFile = 0;
72105
+ let windowLen = await readSource(source, 0, windowBytes, window2, 0);
72106
+ let bytesRead = windowLen;
72107
+ const input2 = new ParsingBuffer(window2, 0, windowLen);
72108
+ const [header, headerResult] = parser211.parseHeader(input2);
72109
+ if (headerResult !== ParseResult.COMPLETE) {
72110
+ return {
72111
+ header,
72112
+ elements: [],
72113
+ result: headerResult,
72114
+ stats: { pool: pool3, windowBytes, slides: 0, maxRecordLen: 0, bytesRead }
72115
+ };
72116
+ }
72117
+ const slideThreshold = windowBytes >> 1;
72118
+ let slides = 0;
72119
+ let maxRecordLen = 0;
72120
+ let prevBoundaryFile = windowStartFile + input2.cursor;
72121
+ const onRecordBoundary = (buffer) => {
72122
+ const cursor = buffer.cursor;
72123
+ const recordFileStart = windowStartFile + cursor;
72124
+ const recordLen = recordFileStart - prevBoundaryFile;
72125
+ if (recordLen > maxRecordLen) {
72126
+ maxRecordLen = recordLen;
72127
+ }
72128
+ prevBoundaryFile = recordFileStart;
72129
+ if (windowStartFile + windowLen >= fileSize) {
72130
+ return;
72131
+ }
72132
+ if (cursor < slideThreshold) {
72133
+ return;
72134
+ }
72135
+ const tail = windowLen - cursor;
72136
+ window2.copyWithin(0, cursor, windowLen);
72137
+ const want = windowBytes - tail;
72138
+ const fillAt = windowStartFile + windowLen;
72139
+ return readSource(source, fillAt, want, window2, tail).then((got) => {
72140
+ bytesRead += got;
72141
+ windowLen = tail + got;
72142
+ windowStartFile = recordFileStart;
72143
+ buffer.rebaseWindow(window2, 0, windowLen, windowStartFile);
72144
+ ++slides;
72145
+ });
72146
+ };
72147
+ const progressTick = onProgress !== void 0 ? (cursor) => onProgress(windowStartFile + cursor) : void 0;
72148
+ const [index, result] = await parser211.parseDataBlockStreamedAsync(input2, onRecordBoundary, onRecordIndexed, progressTick, sink, yieldIntervalMs);
72149
+ const stoppedShort = result !== ParseResult.COMPLETE;
72150
+ const notAtEof = windowStartFile + windowLen < fileSize;
72151
+ if (stoppedShort && notAtEof) {
72152
+ windowBytes *= 2;
72153
+ sink?.reset();
72154
+ continue;
72155
+ }
72156
+ const lastRecordLen = windowStartFile + input2.cursor - prevBoundaryFile;
72157
+ if (lastRecordLen > maxRecordLen) {
72158
+ maxRecordLen = lastRecordLen;
72159
+ }
72160
+ return {
72161
+ header,
72162
+ elements: index.elements,
72163
+ result,
72164
+ stats: { pool: pool3, windowBytes, slides, maxRecordLen, bytesRead }
72165
+ };
72166
+ }
72167
+ }
72168
+ function buildColumnarIndexStreaming(source, parser211, pool3, onRecordIndexed, sink = new ColumnarIndexSink()) {
72169
+ const { header, result, stats } = buildIndexStreaming(source, parser211, pool3, onRecordIndexed, sink);
72170
+ return { header, columns: sink.finalize(), result, stats };
72171
+ }
72172
+ async function buildColumnarIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, onProgress, yieldIntervalMs, sink = new ColumnarIndexSink()) {
72173
+ const { header, result, stats } = await buildIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, sink, onProgress, yieldIntervalMs);
72174
+ return { header, columns: sink.finalize(), result, stats };
72175
+ }
72176
+
70715
72177
  // compiled/src/ifc/ifc_step_parser.js
72178
+ var DEFAULT_STREAM_POOL_BYTES = 1024 * 1024;
70716
72179
  var IfcStepParser = class extends StepParser {
70717
72180
  /**
70718
72181
  * Construct the IFC step parser.
@@ -70745,6 +72208,61 @@ var IfcStepParser = class extends StepParser {
70745
72208
  const [itemIndex, parseResult2] = await this.parseDataBlockAsync(input2, onProgress);
70746
72209
  return [parseResult2, new IfcStepModel(input2.buffer, itemIndex.elements)];
70747
72210
  }
72211
+ /**
72212
+ * Build a model by streaming the source through a bounded moving window
72213
+ * (see buildIndexStreaming / M0) rather than parsing one resident buffer,
72214
+ * then backing the model with a windowed provider over `store` — so the
72215
+ * source is never held fully resident in the JS heap.
72216
+ *
72217
+ * `source` serves the parse (synchronous windowed reads — on a worker this
72218
+ * is an OPFS sync-access handle; in node/tests a file descriptor or buffer)
72219
+ * and `store` serves the model's post-parse property access (asynchronous
72220
+ * windowed reads paged in on demand — OPFS `File.slice()` in the browser).
72221
+ * Both view the same file bytes, so the file-absolute addresses the index
72222
+ * records resolve identically through either.
72223
+ *
72224
+ * NOTE (M1 scope): this delivers the bounded-memory *parse*. Synchronous
72225
+ * geometry extraction still needs its record ranges resident — as after
72226
+ * `spillSourceToExternalStore` — so a caller that extracts geometry must
72227
+ * `ensureResident` first (demand-driven geometry is M3). Property / index
72228
+ * access works directly via the async surfaces.
72229
+ *
72230
+ * @param source Synchronous byte source feeding the streaming parse.
72231
+ * @param store Async external store backing the windowed model.
72232
+ * @param opts Optional window sizing: `pool` (parse window),
72233
+ * `chunkBytes` / `maxResidentChunks` (model window).
72234
+ * @return {[ParseResult, IfcStepModel | undefined]} The parse result and
72235
+ * the windowed model.
72236
+ */
72237
+ parseStreamToModel(source, store, opts) {
72238
+ if (store.byteLength !== source.byteLength) {
72239
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match source byteLength ${source.byteLength}`);
72240
+ }
72241
+ const { columns, result } = buildColumnarIndexStreaming(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES);
72242
+ const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
72243
+ return [result, new IfcStepModel(void 0, columns, provider)];
72244
+ }
72245
+ /**
72246
+ * Cooperative twin of {@link parseStreamToModel}: the index build
72247
+ * yields to the event loop and can fill windows from an async
72248
+ * {@link ReadableByteSource} (an OPFS `File.slice()` store). The
72249
+ * model is still windowed — geometry extract must
72250
+ * `ensureResident` first.
72251
+ *
72252
+ * @param source Sync or async byte source feeding the parse.
72253
+ * @param store Async external store backing the windowed model.
72254
+ * @param opts Optional window sizing plus parse progress.
72255
+ * @return {Promise<[ParseResult, IfcStepModel | undefined]>} The
72256
+ * parse result and the windowed model.
72257
+ */
72258
+ async parseStreamToModelAsync(source, store, opts) {
72259
+ if (store.byteLength !== source.byteLength) {
72260
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match source byteLength ${source.byteLength}`);
72261
+ }
72262
+ const { columns, result } = await buildColumnarIndexStreamingAsync(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES, void 0, opts?.onProgress);
72263
+ const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
72264
+ return [result, new IfcStepModel(void 0, columns, provider)];
72265
+ }
70748
72266
  };
70749
72267
  IfcStepParser.Instance = new IfcStepParser();
70750
72268
  var ifc_step_parser_default = IfcStepParser;