@bldrs-ai/conway 1.398.1224 → 1.400.1226

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.
@@ -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.398.1224";
33
+ var versionString = "Conway v1.400.1226";
34
34
 
35
35
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
36
36
  var wasmType = "";
@@ -4975,18 +4975,24 @@ var StepModelBase = class {
4975
4975
  * Construct this step model with its matching schema, a buffer to read from and an element index.
4976
4976
  *
4977
4977
  * @param schema The Step schema this is based on.
4978
- * @param buffer_ The buffer to read this from.
4978
+ * @param buffer_ The buffer to read this from. Pass `undefined` together
4979
+ * with `provider` to build a model whose source is windowed from
4980
+ * construction (e.g. a streaming open — see buildModelStreaming); the
4981
+ * synchronous read paths (geometry extraction) then require the relevant
4982
+ * ranges to be resident, exactly as after `spillSourceToExternalStore`.
4979
4983
  * @param elementIndex The element index for this, parsed or deserialized - note this takes
4980
4984
  * ownership of this array in the sense it will modify values/unfold inline elements etc.
4985
+ * @param provider Optional pre-built buffer provider. When omitted, a
4986
+ * resident provider over `buffer_` is used (the classic path).
4981
4987
  */
4982
- constructor(schema, buffer_, elementIndex) {
4988
+ constructor(schema, buffer_, elementIndex, provider) {
4983
4989
  this.schema = schema;
4984
4990
  this.buffer_ = buffer_;
4985
4991
  this.vtableBuilder_ = new StepVtableBuilder();
4986
4992
  this.descriptorCache_ = [];
4987
4993
  this.elementMemoization = true;
4988
4994
  this.nullOnErrors = true;
4989
- this.bufferProvider_ = new ResidentStepBufferProvider(buffer_);
4995
+ this.bufferProvider_ = provider ?? new ResidentStepBufferProvider(buffer_);
4990
4996
  const localElementIndex = elementIndex;
4991
4997
  let where = 0;
4992
4998
  const firstInlineElement = localElementIndex.length;
@@ -70749,11 +70755,13 @@ var IfcStepModel = class extends StepModelBase {
70749
70755
  * Construct this model given a buffer containing the data and the parsed data index on that,
70750
70756
  * adding the typeIndex on top of that.
70751
70757
  *
70752
- * @param buffer The buffer to values from.
70758
+ * @param buffer The buffer to values from, or `undefined` with `provider`
70759
+ * set for a windowed (streaming) source.
70753
70760
  * @param elementIndex The parsed index to elements in the STEP.
70761
+ * @param provider Optional pre-built buffer provider (windowed source).
70754
70762
  */
70755
- constructor(buffer, elementIndex) {
70756
- super(schema_ifc_gen_default, buffer, elementIndex);
70763
+ constructor(buffer, elementIndex, provider) {
70764
+ super(schema_ifc_gen_default, buffer, elementIndex, provider);
70757
70765
  this.externalMappingType = ifc_step_external_mapping_default;
70758
70766
  this.geometry = new IfcModelGeometry(this);
70759
70767
  this.voidGeometry = new IfcModelGeometry(this, true);
@@ -70767,7 +70775,76 @@ var IfcStepModel = class extends StepModelBase {
70767
70775
  }
70768
70776
  };
70769
70777
 
70778
+ // compiled/src/step/parsing/streaming_index_builder.js
70779
+ function buildIndexStreaming(source, parser211, pool3) {
70780
+ const fileSize = source.byteLength;
70781
+ let windowBytes = Math.max(pool3, MIN_WINDOW);
70782
+ for (; ; ) {
70783
+ const window2 = new Uint8Array(windowBytes);
70784
+ let windowStartFile = 0;
70785
+ let windowLen = source.read(0, windowBytes, window2, 0);
70786
+ let bytesRead = windowLen;
70787
+ const input2 = new ParsingBuffer(window2, 0, windowLen);
70788
+ const [header, headerResult] = parser211.parseHeader(input2);
70789
+ if (headerResult !== ParseResult.COMPLETE) {
70790
+ return {
70791
+ header,
70792
+ elements: [],
70793
+ result: headerResult,
70794
+ stats: { pool: pool3, windowBytes, slides: 0, maxRecordLen: 0, bytesRead }
70795
+ };
70796
+ }
70797
+ const slideThreshold = windowBytes >> 1;
70798
+ let slides = 0;
70799
+ let maxRecordLen = 0;
70800
+ let prevBoundaryFile = windowStartFile + input2.cursor;
70801
+ const onRecordBoundary = (buffer) => {
70802
+ const cursor = buffer.cursor;
70803
+ const recordFileStart = windowStartFile + cursor;
70804
+ const recordLen = recordFileStart - prevBoundaryFile;
70805
+ if (recordLen > maxRecordLen) {
70806
+ maxRecordLen = recordLen;
70807
+ }
70808
+ prevBoundaryFile = recordFileStart;
70809
+ if (windowStartFile + windowLen >= fileSize) {
70810
+ return;
70811
+ }
70812
+ if (cursor < slideThreshold) {
70813
+ return;
70814
+ }
70815
+ const tail = windowLen - cursor;
70816
+ window2.copyWithin(0, cursor, windowLen);
70817
+ const want = windowBytes - tail;
70818
+ const got = source.read(windowStartFile + windowLen, want, window2, tail);
70819
+ bytesRead += got;
70820
+ windowLen = tail + got;
70821
+ windowStartFile = recordFileStart;
70822
+ buffer.rebaseWindow(window2, 0, windowLen, windowStartFile);
70823
+ ++slides;
70824
+ };
70825
+ const [index, result] = parser211.parseDataBlockStreamed(input2, onRecordBoundary);
70826
+ const stoppedShort = result !== ParseResult.COMPLETE;
70827
+ const notAtEof = windowStartFile + windowLen < fileSize;
70828
+ if (stoppedShort && notAtEof) {
70829
+ windowBytes *= 2;
70830
+ continue;
70831
+ }
70832
+ const lastRecordLen = windowStartFile + input2.cursor - prevBoundaryFile;
70833
+ if (lastRecordLen > maxRecordLen) {
70834
+ maxRecordLen = lastRecordLen;
70835
+ }
70836
+ return {
70837
+ header,
70838
+ elements: index.elements,
70839
+ result,
70840
+ stats: { pool: pool3, windowBytes, slides, maxRecordLen, bytesRead }
70841
+ };
70842
+ }
70843
+ }
70844
+ var MIN_WINDOW = 4 * 1024;
70845
+
70770
70846
  // compiled/src/ifc/ifc_step_parser.js
70847
+ var DEFAULT_STREAM_POOL_BYTES = 1024 * 1024;
70771
70848
  var IfcStepParser = class extends StepParser {
70772
70849
  /**
70773
70850
  * Construct the IFC step parser.
@@ -70800,6 +70877,40 @@ var IfcStepParser = class extends StepParser {
70800
70877
  const [itemIndex, parseResult2] = await this.parseDataBlockAsync(input2, onProgress);
70801
70878
  return [parseResult2, new IfcStepModel(input2.buffer, itemIndex.elements)];
70802
70879
  }
70880
+ /**
70881
+ * Build a model by streaming the source through a bounded moving window
70882
+ * (see buildIndexStreaming / M0) rather than parsing one resident buffer,
70883
+ * then backing the model with a windowed provider over `store` — so the
70884
+ * source is never held fully resident in the JS heap.
70885
+ *
70886
+ * `source` serves the parse (synchronous windowed reads — on a worker this
70887
+ * is an OPFS sync-access handle; in node/tests a file descriptor or buffer)
70888
+ * and `store` serves the model's post-parse property access (asynchronous
70889
+ * windowed reads paged in on demand — OPFS `File.slice()` in the browser).
70890
+ * Both view the same file bytes, so the file-absolute addresses the index
70891
+ * records resolve identically through either.
70892
+ *
70893
+ * NOTE (M1 scope): this delivers the bounded-memory *parse*. Synchronous
70894
+ * geometry extraction still needs its record ranges resident — as after
70895
+ * `spillSourceToExternalStore` — so a caller that extracts geometry must
70896
+ * `ensureResident` first (demand-driven geometry is M3). Property / index
70897
+ * access works directly via the async surfaces.
70898
+ *
70899
+ * @param source Synchronous byte source feeding the streaming parse.
70900
+ * @param store Async external store backing the windowed model.
70901
+ * @param opts Optional window sizing: `pool` (parse window),
70902
+ * `chunkBytes` / `maxResidentChunks` (model window).
70903
+ * @return {[ParseResult, IfcStepModel | undefined]} The parse result and
70904
+ * the windowed model.
70905
+ */
70906
+ parseStreamToModel(source, store, opts) {
70907
+ if (store.byteLength !== source.byteLength) {
70908
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match source byteLength ${source.byteLength}`);
70909
+ }
70910
+ const { elements, result } = buildIndexStreaming(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES);
70911
+ const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
70912
+ return [result, new IfcStepModel(void 0, elements, provider)];
70913
+ }
70803
70914
  };
70804
70915
  IfcStepParser.Instance = new IfcStepParser();
70805
70916
  var ifc_step_parser_default = IfcStepParser;
@@ -14965,7 +14965,7 @@ ${t5.join("\n")}` : "";
14965
14965
  var import_process = require("process");
14966
14966
 
14967
14967
  // compiled/src/version/version.js
14968
- var versionString = "Conway v1.398.1224";
14968
+ var versionString = "Conway v1.400.1226";
14969
14969
 
14970
14970
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
14971
14971
  function pThreadsAllowed() {
@@ -20789,18 +20789,24 @@ var StepModelBase = class {
20789
20789
  * Construct this step model with its matching schema, a buffer to read from and an element index.
20790
20790
  *
20791
20791
  * @param schema The Step schema this is based on.
20792
- * @param buffer_ The buffer to read this from.
20792
+ * @param buffer_ The buffer to read this from. Pass `undefined` together
20793
+ * with `provider` to build a model whose source is windowed from
20794
+ * construction (e.g. a streaming open — see buildModelStreaming); the
20795
+ * synchronous read paths (geometry extraction) then require the relevant
20796
+ * ranges to be resident, exactly as after `spillSourceToExternalStore`.
20793
20797
  * @param elementIndex The element index for this, parsed or deserialized - note this takes
20794
20798
  * ownership of this array in the sense it will modify values/unfold inline elements etc.
20799
+ * @param provider Optional pre-built buffer provider. When omitted, a
20800
+ * resident provider over `buffer_` is used (the classic path).
20795
20801
  */
20796
- constructor(schema, buffer_, elementIndex) {
20802
+ constructor(schema, buffer_, elementIndex, provider) {
20797
20803
  this.schema = schema;
20798
20804
  this.buffer_ = buffer_;
20799
20805
  this.vtableBuilder_ = new StepVtableBuilder();
20800
20806
  this.descriptorCache_ = [];
20801
20807
  this.elementMemoization = true;
20802
20808
  this.nullOnErrors = true;
20803
- this.bufferProvider_ = new ResidentStepBufferProvider(buffer_);
20809
+ this.bufferProvider_ = provider ?? new ResidentStepBufferProvider(buffer_);
20804
20810
  const localElementIndex = elementIndex;
20805
20811
  let where = 0;
20806
20812
  const firstInlineElement = localElementIndex.length;
@@ -86594,11 +86600,13 @@ var IfcStepModel = class extends StepModelBase {
86594
86600
  * Construct this model given a buffer containing the data and the parsed data index on that,
86595
86601
  * adding the typeIndex on top of that.
86596
86602
  *
86597
- * @param buffer The buffer to values from.
86603
+ * @param buffer The buffer to values from, or `undefined` with `provider`
86604
+ * set for a windowed (streaming) source.
86598
86605
  * @param elementIndex The parsed index to elements in the STEP.
86606
+ * @param provider Optional pre-built buffer provider (windowed source).
86599
86607
  */
86600
- constructor(buffer, elementIndex) {
86601
- super(schema_ifc_gen_default, buffer, elementIndex);
86608
+ constructor(buffer, elementIndex, provider) {
86609
+ super(schema_ifc_gen_default, buffer, elementIndex, provider);
86602
86610
  this.externalMappingType = ifc_step_external_mapping_default;
86603
86611
  this.geometry = new IfcModelGeometry(this);
86604
86612
  this.voidGeometry = new IfcModelGeometry(this, true);
@@ -86612,7 +86620,76 @@ var IfcStepModel = class extends StepModelBase {
86612
86620
  }
86613
86621
  };
86614
86622
 
86623
+ // compiled/src/step/parsing/streaming_index_builder.js
86624
+ function buildIndexStreaming(source, parser210, pool3) {
86625
+ const fileSize = source.byteLength;
86626
+ let windowBytes = Math.max(pool3, MIN_WINDOW);
86627
+ for (; ; ) {
86628
+ const window2 = new Uint8Array(windowBytes);
86629
+ let windowStartFile = 0;
86630
+ let windowLen = source.read(0, windowBytes, window2, 0);
86631
+ let bytesRead = windowLen;
86632
+ const input = new ParsingBuffer(window2, 0, windowLen);
86633
+ const [header, headerResult] = parser210.parseHeader(input);
86634
+ if (headerResult !== ParseResult.COMPLETE) {
86635
+ return {
86636
+ header,
86637
+ elements: [],
86638
+ result: headerResult,
86639
+ stats: { pool: pool3, windowBytes, slides: 0, maxRecordLen: 0, bytesRead }
86640
+ };
86641
+ }
86642
+ const slideThreshold = windowBytes >> 1;
86643
+ let slides = 0;
86644
+ let maxRecordLen = 0;
86645
+ let prevBoundaryFile = windowStartFile + input.cursor;
86646
+ const onRecordBoundary = (buffer) => {
86647
+ const cursor = buffer.cursor;
86648
+ const recordFileStart = windowStartFile + cursor;
86649
+ const recordLen = recordFileStart - prevBoundaryFile;
86650
+ if (recordLen > maxRecordLen) {
86651
+ maxRecordLen = recordLen;
86652
+ }
86653
+ prevBoundaryFile = recordFileStart;
86654
+ if (windowStartFile + windowLen >= fileSize) {
86655
+ return;
86656
+ }
86657
+ if (cursor < slideThreshold) {
86658
+ return;
86659
+ }
86660
+ const tail = windowLen - cursor;
86661
+ window2.copyWithin(0, cursor, windowLen);
86662
+ const want = windowBytes - tail;
86663
+ const got = source.read(windowStartFile + windowLen, want, window2, tail);
86664
+ bytesRead += got;
86665
+ windowLen = tail + got;
86666
+ windowStartFile = recordFileStart;
86667
+ buffer.rebaseWindow(window2, 0, windowLen, windowStartFile);
86668
+ ++slides;
86669
+ };
86670
+ const [index, result] = parser210.parseDataBlockStreamed(input, onRecordBoundary);
86671
+ const stoppedShort = result !== ParseResult.COMPLETE;
86672
+ const notAtEof = windowStartFile + windowLen < fileSize;
86673
+ if (stoppedShort && notAtEof) {
86674
+ windowBytes *= 2;
86675
+ continue;
86676
+ }
86677
+ const lastRecordLen = windowStartFile + input.cursor - prevBoundaryFile;
86678
+ if (lastRecordLen > maxRecordLen) {
86679
+ maxRecordLen = lastRecordLen;
86680
+ }
86681
+ return {
86682
+ header,
86683
+ elements: index.elements,
86684
+ result,
86685
+ stats: { pool: pool3, windowBytes, slides, maxRecordLen, bytesRead }
86686
+ };
86687
+ }
86688
+ }
86689
+ var MIN_WINDOW = 4 * 1024;
86690
+
86615
86691
  // compiled/src/ifc/ifc_step_parser.js
86692
+ var DEFAULT_STREAM_POOL_BYTES = 1024 * 1024;
86616
86693
  var IfcStepParser = class extends StepParser {
86617
86694
  /**
86618
86695
  * Construct the IFC step parser.
@@ -86645,6 +86722,40 @@ var IfcStepParser = class extends StepParser {
86645
86722
  const [itemIndex, parseResult] = await this.parseDataBlockAsync(input, onProgress);
86646
86723
  return [parseResult, new IfcStepModel(input.buffer, itemIndex.elements)];
86647
86724
  }
86725
+ /**
86726
+ * Build a model by streaming the source through a bounded moving window
86727
+ * (see buildIndexStreaming / M0) rather than parsing one resident buffer,
86728
+ * then backing the model with a windowed provider over `store` — so the
86729
+ * source is never held fully resident in the JS heap.
86730
+ *
86731
+ * `source` serves the parse (synchronous windowed reads — on a worker this
86732
+ * is an OPFS sync-access handle; in node/tests a file descriptor or buffer)
86733
+ * and `store` serves the model's post-parse property access (asynchronous
86734
+ * windowed reads paged in on demand — OPFS `File.slice()` in the browser).
86735
+ * Both view the same file bytes, so the file-absolute addresses the index
86736
+ * records resolve identically through either.
86737
+ *
86738
+ * NOTE (M1 scope): this delivers the bounded-memory *parse*. Synchronous
86739
+ * geometry extraction still needs its record ranges resident — as after
86740
+ * `spillSourceToExternalStore` — so a caller that extracts geometry must
86741
+ * `ensureResident` first (demand-driven geometry is M3). Property / index
86742
+ * access works directly via the async surfaces.
86743
+ *
86744
+ * @param source Synchronous byte source feeding the streaming parse.
86745
+ * @param store Async external store backing the windowed model.
86746
+ * @param opts Optional window sizing: `pool` (parse window),
86747
+ * `chunkBytes` / `maxResidentChunks` (model window).
86748
+ * @return {[ParseResult, IfcStepModel | undefined]} The parse result and
86749
+ * the windowed model.
86750
+ */
86751
+ parseStreamToModel(source, store, opts) {
86752
+ if (store.byteLength !== source.byteLength) {
86753
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match source byteLength ${source.byteLength}`);
86754
+ }
86755
+ const { elements, result } = buildIndexStreaming(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES);
86756
+ const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
86757
+ return [result, new IfcStepModel(void 0, elements, provider)];
86758
+ }
86648
86759
  };
86649
86760
  IfcStepParser.Instance = new IfcStepParser();
86650
86761
  var ifc_step_parser_default = IfcStepParser;
@@ -15943,7 +15943,7 @@ var ParsingBuffer = class {
15943
15943
  };
15944
15944
 
15945
15945
  // compiled/src/version/version.js
15946
- var versionString = "Conway v1.398.1224";
15946
+ var versionString = "Conway v1.400.1226";
15947
15947
 
15948
15948
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
15949
15949
  function pThreadsAllowed() {
@@ -20580,18 +20580,24 @@ var StepModelBase = class {
20580
20580
  * Construct this step model with its matching schema, a buffer to read from and an element index.
20581
20581
  *
20582
20582
  * @param schema The Step schema this is based on.
20583
- * @param buffer_ The buffer to read this from.
20583
+ * @param buffer_ The buffer to read this from. Pass `undefined` together
20584
+ * with `provider` to build a model whose source is windowed from
20585
+ * construction (e.g. a streaming open — see buildModelStreaming); the
20586
+ * synchronous read paths (geometry extraction) then require the relevant
20587
+ * ranges to be resident, exactly as after `spillSourceToExternalStore`.
20584
20588
  * @param elementIndex The element index for this, parsed or deserialized - note this takes
20585
20589
  * ownership of this array in the sense it will modify values/unfold inline elements etc.
20590
+ * @param provider Optional pre-built buffer provider. When omitted, a
20591
+ * resident provider over `buffer_` is used (the classic path).
20586
20592
  */
20587
- constructor(schema, buffer_, elementIndex) {
20593
+ constructor(schema, buffer_, elementIndex, provider) {
20588
20594
  this.schema = schema;
20589
20595
  this.buffer_ = buffer_;
20590
20596
  this.vtableBuilder_ = new StepVtableBuilder();
20591
20597
  this.descriptorCache_ = [];
20592
20598
  this.elementMemoization = true;
20593
20599
  this.nullOnErrors = true;
20594
- this.bufferProvider_ = new ResidentStepBufferProvider(buffer_);
20600
+ this.bufferProvider_ = provider ?? new ResidentStepBufferProvider(buffer_);
20595
20601
  const localElementIndex = elementIndex;
20596
20602
  let where = 0;
20597
20603
  const firstInlineElement = localElementIndex.length;
@@ -944,7 +944,7 @@ var EntityTypesIfcCount = 909;
944
944
  var entity_types_ifc_gen_default = EntityTypesIfc;
945
945
 
946
946
  // compiled/src/version/version.js
947
- var versionString = "Conway v1.398.1224";
947
+ var versionString = "Conway v1.400.1226";
948
948
 
949
949
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
950
950
  var wasmType = "";
@@ -4973,18 +4973,24 @@ var StepModelBase = class {
4973
4973
  * Construct this step model with its matching schema, a buffer to read from and an element index.
4974
4974
  *
4975
4975
  * @param schema The Step schema this is based on.
4976
- * @param buffer_ The buffer to read this from.
4976
+ * @param buffer_ The buffer to read this from. Pass `undefined` together
4977
+ * with `provider` to build a model whose source is windowed from
4978
+ * construction (e.g. a streaming open — see buildModelStreaming); the
4979
+ * synchronous read paths (geometry extraction) then require the relevant
4980
+ * ranges to be resident, exactly as after `spillSourceToExternalStore`.
4977
4981
  * @param elementIndex The element index for this, parsed or deserialized - note this takes
4978
4982
  * ownership of this array in the sense it will modify values/unfold inline elements etc.
4983
+ * @param provider Optional pre-built buffer provider. When omitted, a
4984
+ * resident provider over `buffer_` is used (the classic path).
4979
4985
  */
4980
- constructor(schema, buffer_, elementIndex) {
4986
+ constructor(schema, buffer_, elementIndex, provider) {
4981
4987
  this.schema = schema;
4982
4988
  this.buffer_ = buffer_;
4983
4989
  this.vtableBuilder_ = new StepVtableBuilder();
4984
4990
  this.descriptorCache_ = [];
4985
4991
  this.elementMemoization = true;
4986
4992
  this.nullOnErrors = true;
4987
- this.bufferProvider_ = new ResidentStepBufferProvider(buffer_);
4993
+ this.bufferProvider_ = provider ?? new ResidentStepBufferProvider(buffer_);
4988
4994
  const localElementIndex = elementIndex;
4989
4995
  let where = 0;
4990
4996
  const firstInlineElement = localElementIndex.length;
@@ -70747,11 +70753,13 @@ var IfcStepModel = class extends StepModelBase {
70747
70753
  * Construct this model given a buffer containing the data and the parsed data index on that,
70748
70754
  * adding the typeIndex on top of that.
70749
70755
  *
70750
- * @param buffer The buffer to values from.
70756
+ * @param buffer The buffer to values from, or `undefined` with `provider`
70757
+ * set for a windowed (streaming) source.
70751
70758
  * @param elementIndex The parsed index to elements in the STEP.
70759
+ * @param provider Optional pre-built buffer provider (windowed source).
70752
70760
  */
70753
- constructor(buffer, elementIndex) {
70754
- super(schema_ifc_gen_default, buffer, elementIndex);
70761
+ constructor(buffer, elementIndex, provider) {
70762
+ super(schema_ifc_gen_default, buffer, elementIndex, provider);
70755
70763
  this.externalMappingType = ifc_step_external_mapping_default;
70756
70764
  this.geometry = new IfcModelGeometry(this);
70757
70765
  this.voidGeometry = new IfcModelGeometry(this, true);
@@ -70765,7 +70773,76 @@ var IfcStepModel = class extends StepModelBase {
70765
70773
  }
70766
70774
  };
70767
70775
 
70776
+ // compiled/src/step/parsing/streaming_index_builder.js
70777
+ function buildIndexStreaming(source, parser211, pool3) {
70778
+ const fileSize = source.byteLength;
70779
+ let windowBytes = Math.max(pool3, MIN_WINDOW);
70780
+ for (; ; ) {
70781
+ const window2 = new Uint8Array(windowBytes);
70782
+ let windowStartFile = 0;
70783
+ let windowLen = source.read(0, windowBytes, window2, 0);
70784
+ let bytesRead = windowLen;
70785
+ const input = new ParsingBuffer(window2, 0, windowLen);
70786
+ const [header, headerResult] = parser211.parseHeader(input);
70787
+ if (headerResult !== ParseResult.COMPLETE) {
70788
+ return {
70789
+ header,
70790
+ elements: [],
70791
+ result: headerResult,
70792
+ stats: { pool: pool3, windowBytes, slides: 0, maxRecordLen: 0, bytesRead }
70793
+ };
70794
+ }
70795
+ const slideThreshold = windowBytes >> 1;
70796
+ let slides = 0;
70797
+ let maxRecordLen = 0;
70798
+ let prevBoundaryFile = windowStartFile + input.cursor;
70799
+ const onRecordBoundary = (buffer) => {
70800
+ const cursor = buffer.cursor;
70801
+ const recordFileStart = windowStartFile + cursor;
70802
+ const recordLen = recordFileStart - prevBoundaryFile;
70803
+ if (recordLen > maxRecordLen) {
70804
+ maxRecordLen = recordLen;
70805
+ }
70806
+ prevBoundaryFile = recordFileStart;
70807
+ if (windowStartFile + windowLen >= fileSize) {
70808
+ return;
70809
+ }
70810
+ if (cursor < slideThreshold) {
70811
+ return;
70812
+ }
70813
+ const tail = windowLen - cursor;
70814
+ window2.copyWithin(0, cursor, windowLen);
70815
+ const want = windowBytes - tail;
70816
+ const got = source.read(windowStartFile + windowLen, want, window2, tail);
70817
+ bytesRead += got;
70818
+ windowLen = tail + got;
70819
+ windowStartFile = recordFileStart;
70820
+ buffer.rebaseWindow(window2, 0, windowLen, windowStartFile);
70821
+ ++slides;
70822
+ };
70823
+ const [index, result] = parser211.parseDataBlockStreamed(input, onRecordBoundary);
70824
+ const stoppedShort = result !== ParseResult.COMPLETE;
70825
+ const notAtEof = windowStartFile + windowLen < fileSize;
70826
+ if (stoppedShort && notAtEof) {
70827
+ windowBytes *= 2;
70828
+ continue;
70829
+ }
70830
+ const lastRecordLen = windowStartFile + input.cursor - prevBoundaryFile;
70831
+ if (lastRecordLen > maxRecordLen) {
70832
+ maxRecordLen = lastRecordLen;
70833
+ }
70834
+ return {
70835
+ header,
70836
+ elements: index.elements,
70837
+ result,
70838
+ stats: { pool: pool3, windowBytes, slides, maxRecordLen, bytesRead }
70839
+ };
70840
+ }
70841
+ }
70842
+ var MIN_WINDOW = 4 * 1024;
70843
+
70768
70844
  // compiled/src/ifc/ifc_step_parser.js
70845
+ var DEFAULT_STREAM_POOL_BYTES = 1024 * 1024;
70769
70846
  var IfcStepParser = class extends StepParser {
70770
70847
  /**
70771
70848
  * Construct the IFC step parser.
@@ -70798,6 +70875,40 @@ var IfcStepParser = class extends StepParser {
70798
70875
  const [itemIndex, parseResult2] = await this.parseDataBlockAsync(input, onProgress);
70799
70876
  return [parseResult2, new IfcStepModel(input.buffer, itemIndex.elements)];
70800
70877
  }
70878
+ /**
70879
+ * Build a model by streaming the source through a bounded moving window
70880
+ * (see buildIndexStreaming / M0) rather than parsing one resident buffer,
70881
+ * then backing the model with a windowed provider over `store` — so the
70882
+ * source is never held fully resident in the JS heap.
70883
+ *
70884
+ * `source` serves the parse (synchronous windowed reads — on a worker this
70885
+ * is an OPFS sync-access handle; in node/tests a file descriptor or buffer)
70886
+ * and `store` serves the model's post-parse property access (asynchronous
70887
+ * windowed reads paged in on demand — OPFS `File.slice()` in the browser).
70888
+ * Both view the same file bytes, so the file-absolute addresses the index
70889
+ * records resolve identically through either.
70890
+ *
70891
+ * NOTE (M1 scope): this delivers the bounded-memory *parse*. Synchronous
70892
+ * geometry extraction still needs its record ranges resident — as after
70893
+ * `spillSourceToExternalStore` — so a caller that extracts geometry must
70894
+ * `ensureResident` first (demand-driven geometry is M3). Property / index
70895
+ * access works directly via the async surfaces.
70896
+ *
70897
+ * @param source Synchronous byte source feeding the streaming parse.
70898
+ * @param store Async external store backing the windowed model.
70899
+ * @param opts Optional window sizing: `pool` (parse window),
70900
+ * `chunkBytes` / `maxResidentChunks` (model window).
70901
+ * @return {[ParseResult, IfcStepModel | undefined]} The parse result and
70902
+ * the windowed model.
70903
+ */
70904
+ parseStreamToModel(source, store, opts) {
70905
+ if (store.byteLength !== source.byteLength) {
70906
+ throw new Error(`Streaming store byteLength ${store.byteLength} does not match source byteLength ${source.byteLength}`);
70907
+ }
70908
+ const { elements, result } = buildIndexStreaming(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES);
70909
+ const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
70910
+ return [result, new IfcStepModel(void 0, elements, provider)];
70911
+ }
70801
70912
  };
70802
70913
  IfcStepParser.Instance = new IfcStepParser();
70803
70914
  var ifc_step_parser_default = IfcStepParser;
@@ -8,6 +8,7 @@ import IfcStepExternalMapping from "./ifc_step_external_mapping.js";
8
8
  import IfcModelCurves from "./ifc_model_curves.js";
9
9
  import { CsgMemoization } from "../core/csg_operations.js";
10
10
  import { IfcMaterialCache } from "./ifc_material_cache.js";
11
+ import { StepBufferProvider } from "../step/step_buffer_provider.js";
11
12
  /**
12
13
  * Represents an IFC model deserialized from step.
13
14
  */
@@ -26,9 +27,11 @@ export default class IfcStepModel extends StepModelBase<EntityTypesIfc> {
26
27
  * Construct this model given a buffer containing the data and the parsed data index on that,
27
28
  * adding the typeIndex on top of that.
28
29
  *
29
- * @param buffer The buffer to values from.
30
+ * @param buffer The buffer to values from, or `undefined` with `provider`
31
+ * set for a windowed (streaming) source.
30
32
  * @param elementIndex The parsed index to elements in the STEP.
33
+ * @param provider Optional pre-built buffer provider (windowed source).
31
34
  */
32
- constructor(buffer: Uint8Array, elementIndex: StepIndexEntry<EntityTypesIfc>[]);
35
+ constructor(buffer: Uint8Array | undefined, elementIndex: StepIndexEntry<EntityTypesIfc>[], provider?: StepBufferProvider);
33
36
  }
34
37
  //# sourceMappingURL=ifc_step_model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ifc_step_model.d.ts","sourceRoot":"","sources":["../../../src/ifc/ifc_step_model.ts"],"names":[],"mappings":"AAAA,OAAO,cAAqC,MAAM,iCAAiC,CAAA;AACnF,OAAO,aAAa,MAAM,yBAAyB,CAAA;AAEnD,OAAO,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAA;AAE1D,OAAO,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,sBAAsB,MAAM,6BAA6B,CAAA;AAChE,OAAO,cAAc,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAKvD;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,aAAa,CAAE,cAAc,CAAE;IAEvE,SAAgB,SAAS,EAAE,aAAa,CAAE,cAAc,CAAE,CAAA;IAC1D,SAAgB,mBAAmB,gCAAyB;IAC5D,SAAgB,QAAQ,mBAA+B;IACvD,SAAgB,YAAY,mBAAqC;IACjE,SAAgB,QAAQ,kBAA4B;IACpD,SAAgB,MAAM,iBAA2B;IACjD,SAAgB,aAAa,iBAAuB;IACpD,SAAgB,SAAS,mBAA+B;IACxD,SAAgB,aAAa,mBAAqC;IAClE,SAAgB,cAAc,wBAAiB;IAE/C;;;;;;OAMG;gBAEC,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,cAAc,CAAE,cAAc,CAAE,EAAE;CAKrD"}
1
+ {"version":3,"file":"ifc_step_model.d.ts","sourceRoot":"","sources":["../../../src/ifc/ifc_step_model.ts"],"names":[],"mappings":"AAAA,OAAO,cAAqC,MAAM,iCAAiC,CAAA;AACnF,OAAO,aAAa,MAAM,yBAAyB,CAAA;AAEnD,OAAO,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAA;AAE1D,OAAO,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,sBAAsB,MAAM,6BAA6B,CAAA;AAChE,OAAO,cAAc,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAKjE;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,aAAa,CAAE,cAAc,CAAE;IAEvE,SAAgB,SAAS,EAAE,aAAa,CAAE,cAAc,CAAE,CAAA;IAC1D,SAAgB,mBAAmB,gCAAyB;IAC5D,SAAgB,QAAQ,mBAA+B;IACvD,SAAgB,YAAY,mBAAqC;IACjE,SAAgB,QAAQ,kBAA4B;IACpD,SAAgB,MAAM,iBAA2B;IACjD,SAAgB,aAAa,iBAAuB;IACpD,SAAgB,SAAS,mBAA+B;IACxD,SAAgB,aAAa,mBAAqC;IAClE,SAAgB,cAAc,wBAAiB;IAE/C;;;;;;;;OAQG;gBAEC,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,YAAY,EAAE,cAAc,CAAE,cAAc,CAAE,EAAE,EAChD,QAAQ,CAAC,EAAE,kBAAkB;CAKlC"}
@@ -17,11 +17,13 @@ export default class IfcStepModel extends StepModelBase {
17
17
  * Construct this model given a buffer containing the data and the parsed data index on that,
18
18
  * adding the typeIndex on top of that.
19
19
  *
20
- * @param buffer The buffer to values from.
20
+ * @param buffer The buffer to values from, or `undefined` with `provider`
21
+ * set for a windowed (streaming) source.
21
22
  * @param elementIndex The parsed index to elements in the STEP.
23
+ * @param provider Optional pre-built buffer provider (windowed source).
22
24
  */
23
- constructor(buffer, elementIndex) {
24
- super(SchemaIfc, buffer, elementIndex);
25
+ constructor(buffer, elementIndex, provider) {
26
+ super(SchemaIfc, buffer, elementIndex, provider);
25
27
  this.externalMappingType = IfcStepExternalMapping;
26
28
  this.geometry = new IfcModelGeometry(this);
27
29
  this.voidGeometry = new IfcModelGeometry(this, true);
@@ -2,6 +2,8 @@ import ParsingBuffer from "../parsing/parsing_buffer.js";
2
2
  import StepParser, { ParseProgressCallback, ParseResult } from "../step/parsing/step_parser.js";
3
3
  import EntityTypesIfc from "./ifc4_gen/entity_types_ifc.gen.js";
4
4
  import IfcStepModel from "./ifc_step_model.js";
5
+ import { ByteSource } from "../step/parsing/byte_source.js";
6
+ import { StepExternalByteStore } from "../step/step_buffer_provider.js";
5
7
  /**
6
8
  * Parser for taking IFC file serialized in step and turning them into a lazily parsed model.
7
9
  */
@@ -42,5 +44,39 @@ export default class IfcStepParser extends StepParser<EntityTypesIfc> {
42
44
  ParseResult,
43
45
  IfcStepModel | undefined
44
46
  ]>;
47
+ /**
48
+ * Build a model by streaming the source through a bounded moving window
49
+ * (see buildIndexStreaming / M0) rather than parsing one resident buffer,
50
+ * then backing the model with a windowed provider over `store` — so the
51
+ * source is never held fully resident in the JS heap.
52
+ *
53
+ * `source` serves the parse (synchronous windowed reads — on a worker this
54
+ * is an OPFS sync-access handle; in node/tests a file descriptor or buffer)
55
+ * and `store` serves the model's post-parse property access (asynchronous
56
+ * windowed reads paged in on demand — OPFS `File.slice()` in the browser).
57
+ * Both view the same file bytes, so the file-absolute addresses the index
58
+ * records resolve identically through either.
59
+ *
60
+ * NOTE (M1 scope): this delivers the bounded-memory *parse*. Synchronous
61
+ * geometry extraction still needs its record ranges resident — as after
62
+ * `spillSourceToExternalStore` — so a caller that extracts geometry must
63
+ * `ensureResident` first (demand-driven geometry is M3). Property / index
64
+ * access works directly via the async surfaces.
65
+ *
66
+ * @param source Synchronous byte source feeding the streaming parse.
67
+ * @param store Async external store backing the windowed model.
68
+ * @param opts Optional window sizing: `pool` (parse window),
69
+ * `chunkBytes` / `maxResidentChunks` (model window).
70
+ * @return {[ParseResult, IfcStepModel | undefined]} The parse result and
71
+ * the windowed model.
72
+ */
73
+ parseStreamToModel(source: ByteSource, store: StepExternalByteStore, opts?: {
74
+ pool?: number;
75
+ chunkBytes?: number;
76
+ maxResidentChunks?: number;
77
+ }): [
78
+ ParseResult,
79
+ IfcStepModel | undefined
80
+ ];
45
81
  }
46
82
  //# sourceMappingURL=ifc_step_parser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ifc_step_parser.d.ts","sourceRoot":"","sources":["../../../src/ifc/ifc_step_parser.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,2BAA2B,CAAA;AACrD,OAAO,UAAU,EAAE,EAAC,qBAAqB,EAAE,WAAW,EAAC,MAAM,6BAA6B,CAAA;AAC1F,OAAO,cAAc,MAAM,iCAAiC,CAAA;AAE5D,OAAO,YAAY,MAAM,kBAAkB,CAAA;AAE3C;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,UAAU,CAAE,cAAc,CAAE;IACrE;;OAEG;;IAKH;;;;;OAKG;IACH,gBAAuB,QAAQ,gBAAsB;IAErD;;;;;;;OAOG;IACI,gBAAgB,CACnB,KAAK,EAAE,aAAa,EACpB,UAAU,CAAC,EAAE,qBAAqB,GAAI,CAAC,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IAMjF;;;;;;;;OAQG;IACU,qBAAqB,CAC9B,KAAK,EAAE,aAAa,EACpB,UAAU,CAAC,EAAE,qBAAqB,GAClC,OAAO,CAAC,CAAC,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC,CAAC;CAKrD"}
1
+ {"version":3,"file":"ifc_step_parser.d.ts","sourceRoot":"","sources":["../../../src/ifc/ifc_step_parser.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,2BAA2B,CAAA;AACrD,OAAO,UAAU,EAAE,EAAC,qBAAqB,EAAE,WAAW,EAAC,MAAM,6BAA6B,CAAA;AAC1F,OAAO,cAAc,MAAM,iCAAiC,CAAA;AAE5D,OAAO,YAAY,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAExD,OAAO,EACL,qBAAqB,EAEtB,MAAM,8BAA8B,CAAA;AAOrC;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,UAAU,CAAE,cAAc,CAAE;IACrE;;OAEG;;IAKH;;;;;OAKG;IACH,gBAAuB,QAAQ,gBAAsB;IAErD;;;;;;;OAOG;IACI,gBAAgB,CACnB,KAAK,EAAE,aAAa,EACpB,UAAU,CAAC,EAAE,qBAAqB,GAAI,CAAC,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IAMjF;;;;;;;;OAQG;IACU,qBAAqB,CAC9B,KAAK,EAAE,aAAa,EACpB,UAAU,CAAC,EAAE,qBAAqB,GAClC,OAAO,CAAC,CAAC,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC,CAAC;IAMpD;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACI,kBAAkB,CACrB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,qBAAqB,EAC5B,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,GACzE;QAAC,WAAW;QAAE,YAAY,GAAG,SAAS;KAAC;CAgB5C"}