@bldrs-ai/conway 1.510.1439 → 1.512.1444

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 (44) hide show
  1. package/compiled/examples/browser-bundled.cjs +82 -3
  2. package/compiled/examples/cli-bundled.cjs +143 -17
  3. package/compiled/examples/cli-step-bundled.cjs +82 -3
  4. package/compiled/examples/validator-bundled.cjs +82 -3
  5. package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts +3 -2
  6. package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts.map +1 -1
  7. package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.js +29 -7
  8. package/compiled/src/compat/web-ifc/parse_aabb_imposter.d.ts +41 -0
  9. package/compiled/src/compat/web-ifc/parse_aabb_imposter.d.ts.map +1 -0
  10. package/compiled/src/compat/web-ifc/parse_aabb_imposter.js +161 -0
  11. package/compiled/src/compat/web-ifc/parse_aabb_imposter.test.d.ts +2 -0
  12. package/compiled/src/compat/web-ifc/parse_aabb_imposter.test.d.ts.map +1 -0
  13. package/compiled/src/compat/web-ifc/parse_aabb_imposter.test.js +39 -0
  14. package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts +13 -0
  15. package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts.map +1 -1
  16. package/compiled/src/core/progress.d.ts +8 -1
  17. package/compiled/src/core/progress.d.ts.map +1 -1
  18. package/compiled/src/core/progress.js +9 -4
  19. package/compiled/src/core/progress_log.d.ts +1 -0
  20. package/compiled/src/core/progress_log.d.ts.map +1 -1
  21. package/compiled/src/core/progress_log.js +7 -2
  22. package/compiled/src/core/progress_log.test.js +21 -0
  23. package/compiled/src/ifc/ifc_demand_extraction.test.js +12 -1
  24. package/compiled/src/ifc/ifc_geometry_extraction.d.ts +6 -0
  25. package/compiled/src/ifc/ifc_geometry_extraction.d.ts.map +1 -1
  26. package/compiled/src/ifc/ifc_geometry_extraction.js +53 -7
  27. package/compiled/src/ifc/ifc_stream_open.test.js +16 -0
  28. package/compiled/src/step/parsing/step_parser.d.ts +2 -2
  29. package/compiled/src/step/parsing/step_parser.d.ts.map +1 -1
  30. package/compiled/src/step/parsing/step_parser.js +8 -2
  31. package/compiled/src/step/parsing/streaming_index_builder.d.ts +4 -4
  32. package/compiled/src/step/parsing/streaming_index_builder.d.ts.map +1 -1
  33. package/compiled/src/step/step_buffer_provider.d.ts +4 -3
  34. package/compiled/src/step/step_buffer_provider.d.ts.map +1 -1
  35. package/compiled/src/step/step_buffer_provider.js +4 -3
  36. package/compiled/src/step/step_entity_base.d.ts +15 -0
  37. package/compiled/src/step/step_entity_base.d.ts.map +1 -1
  38. package/compiled/src/step/step_entity_base.js +34 -0
  39. package/compiled/src/step/step_model_base.d.ts +18 -0
  40. package/compiled/src/step/step_model_base.d.ts.map +1 -1
  41. package/compiled/src/step/step_model_base.js +40 -0
  42. package/compiled/src/version/version.js +1 -1
  43. package/compiled/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +1 -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.510.1439";
33
+ var versionString = "Conway v1.512.1444";
34
34
 
35
35
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
36
36
  var wasmType = "";
@@ -2910,7 +2910,10 @@ var StepParser = class extends StepHeaderParser {
2910
2910
  if (!charws(SEMICOLON)) {
2911
2911
  return syntaxError();
2912
2912
  }
2913
- onRecordIndexed?.(topLevelCount, expressID, 0);
2913
+ {
2914
+ const recordLen = input2.address - startElement2;
2915
+ onRecordIndexed?.(topLevelCount, expressID, 0, input2.buffer.subarray(input2.cursor - recordLen, input2.cursor));
2916
+ }
2914
2917
  ++topLevelCount;
2915
2918
  pushEntry({
2916
2919
  address: startElement2,
@@ -3000,7 +3003,10 @@ var StepParser = class extends StepHeaderParser {
3000
3003
  if (!charws(SEMICOLON)) {
3001
3004
  return syntaxError();
3002
3005
  }
3003
- onRecordIndexed?.(topLevelCount, expressID, foundItem);
3006
+ {
3007
+ const recordLen = input2.address - startElement;
3008
+ onRecordIndexed?.(topLevelCount, expressID, foundItem, input2.buffer.subarray(input2.cursor - recordLen, input2.cursor));
3009
+ }
3004
3010
  ++topLevelCount;
3005
3011
  pushEntry({
3006
3012
  address: startElement,
@@ -5767,6 +5773,35 @@ var StepModelBase = class {
5767
5773
  }
5768
5774
  this.bufferProvider_.unpinRange?.(this.address_[localID], this.length_[localID]);
5769
5775
  }
5776
+ /**
5777
+ * Drop captured source-window views on `localIDs` so the LRU can
5778
+ * evict those chunks. Vtables stay — `acquire` of the same
5779
+ * `(address, length)` is at a stable base. The next
5780
+ * `ensureResident` + field read rematerialises the view.
5781
+ *
5782
+ * @param localIDs Records whose `buffer` views to drop.
5783
+ */
5784
+ releaseSourceViews(localIDs) {
5785
+ if (!this.isSourceExternal) {
5786
+ return;
5787
+ }
5788
+ for (const localID of localIDs) {
5789
+ if (localID >= this.count_) {
5790
+ continue;
5791
+ }
5792
+ const item = this.complexEntries_?.get(localID) ?? this.descriptorCache_[localID];
5793
+ if (item === void 0) {
5794
+ continue;
5795
+ }
5796
+ item.buffer = void 0;
5797
+ if (item.multiMapping !== void 0) {
5798
+ for (const mapped of item.multiMapping) {
5799
+ mapped.buffer = void 0;
5800
+ }
5801
+ }
5802
+ }
5803
+ releaseScratchParsingBuffer();
5804
+ }
5770
5805
  /**
5771
5806
  * Unpin every local ID in `localIDs` (best-effort; missing IDs are
5772
5807
  * ignored). Use after {@link ensureResidentClosureByLocalID}, which
@@ -5797,6 +5832,17 @@ var StepModelBase = class {
5797
5832
  }
5798
5833
  return this.ensureResidentClosureByLocalID(localID, extraLocalIDs, seen);
5799
5834
  }
5835
+ /**
5836
+ * Express IDs referenced by a resident record (`#<id>` tokens in its
5837
+ * text, including multi-mapped class records). The record itself
5838
+ * must already be resident.
5839
+ *
5840
+ * @param localID The record to scan.
5841
+ * @return {number[]} Distinct referenced express IDs.
5842
+ */
5843
+ referencedExpressIDs(localID) {
5844
+ return this.scanRecordRefs_(localID);
5845
+ }
5800
5846
  /**
5801
5847
  * Scan a resident record's bytes for `#<expressID>` references.
5802
5848
  *
@@ -10982,6 +11028,38 @@ var StepEntityBase = class {
10982
11028
  }
10983
11029
  return value;
10984
11030
  }
11031
+ /**
11032
+ * Resolve a single reference field to its local ID without
11033
+ * constructing the target entity. Prep maps that only store
11034
+ * `Item.localID` (IfcStyledItem → faceset) must not hydrate the
11035
+ * target: on a windowed source that would pin the faceset record
11036
+ * (often megabytes) for every styled item at once.
11037
+ *
11038
+ * @param offset The offset in the vtable to extract from.
11039
+ * @param baseOffset The base offset of the class in the vtable.
11040
+ * @param depth The depth in the inheritance hierarchy.
11041
+ * @param optional Is this an optional field?
11042
+ * @return {number | null} The referenced local ID, or null if the
11043
+ * field is unset/optional-null.
11044
+ */
11045
+ extractReferenceLocalID(offset, baseOffset, depth, optional) {
11046
+ const [cursor, endCursor, buffer] = this.getOffsetAndEndCursor(offset, baseOffset, depth);
11047
+ const expressID = stepExtractReference(buffer, cursor, endCursor);
11048
+ if (expressID !== void 0) {
11049
+ return this.model.resolveExpressID(expressID) ?? null;
11050
+ }
11051
+ const inline = this.model.getInlineElementByAddress(extractInlineElementAddress(buffer, cursor, endCursor));
11052
+ if (inline !== void 0) {
11053
+ return inline.localID;
11054
+ }
11055
+ if (!optional) {
11056
+ throw new Error("Value in STEP was incorrectly typed");
11057
+ }
11058
+ if (!this.model.nullOnErrors && stepExtractOptional(buffer, cursor, endCursor) !== null) {
11059
+ throw new Error("Value in STEP was incorrectly typed");
11060
+ }
11061
+ return null;
11062
+ }
10985
11063
  /**
10986
11064
  *
10987
11065
  * @param buffer
@@ -11299,6 +11377,7 @@ var StepEntityBase = class {
11299
11377
  * @return {Uint8Array} The buffer for this.
11300
11378
  */
11301
11379
  get buffer() {
11380
+ this.guaranteeBuffer();
11302
11381
  return this.internalReference_.buffer;
11303
11382
  }
11304
11383
  /**
@@ -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.510.1439";
14968
+ var versionString = "Conway v1.512.1444";
14969
14969
 
14970
14970
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
14971
14971
  function pThreadsAllowed() {
@@ -16397,13 +16397,15 @@ var ProgressTracker = class {
16397
16397
  * Report progress within the current phase; throttled.
16398
16398
  *
16399
16399
  * @param completed Units completed so far.
16400
+ * @param extras Optional extras (window residency) merged into the event.
16400
16401
  */
16401
- update(completed) {
16402
+ update(completed, extras) {
16403
+ this.extras_ = extras;
16402
16404
  const now = Date.now();
16403
16405
  if (now - this.lastEmitTime < this.minIntervalMs) {
16404
16406
  return;
16405
16407
  }
16406
- this.emit(completed, now);
16408
+ this.emit(completed, now, extras);
16407
16409
  }
16408
16410
  /**
16409
16411
  * End the current phase, emitting an unthrottled final event with
@@ -16412,16 +16414,18 @@ var ProgressTracker = class {
16412
16414
  * @param completed Final completed units (defaults to the phase total).
16413
16415
  */
16414
16416
  endPhase(completed) {
16415
- this.emit(completed ?? this.total_ ?? 0);
16417
+ this.emit(completed ?? this.total_ ?? 0, Date.now(), this.extras_);
16416
16418
  this.phase_ = void 0;
16419
+ this.extras_ = void 0;
16417
16420
  }
16418
16421
  /**
16419
16422
  * Materialize and forward an event now, bypassing the throttle.
16420
16423
  *
16421
16424
  * @param completed Units completed so far.
16422
16425
  * @param now Current time in ms (defaults to Date.now()).
16426
+ * @param extras Optional extras merged into the event.
16423
16427
  */
16424
- emit(completed, now = Date.now()) {
16428
+ emit(completed, now = Date.now(), extras) {
16425
16429
  if (this.phase_ === void 0) {
16426
16430
  return;
16427
16431
  }
@@ -16433,7 +16437,8 @@ var ProgressTracker = class {
16433
16437
  total,
16434
16438
  unit: this.unit_,
16435
16439
  elapsedMs: now - this.startTime,
16436
- memoryMb: Memory.usedHeapMb()
16440
+ memoryMb: Memory.usedHeapMb(),
16441
+ residentSourceMb: extras?.residentSourceMb
16437
16442
  });
16438
16443
  }
16439
16444
  };
@@ -18741,7 +18746,10 @@ var StepParser = class extends StepHeaderParser {
18741
18746
  if (!charws(SEMICOLON)) {
18742
18747
  return syntaxError();
18743
18748
  }
18744
- onRecordIndexed?.(topLevelCount, expressID, 0);
18749
+ {
18750
+ const recordLen = input.address - startElement2;
18751
+ onRecordIndexed?.(topLevelCount, expressID, 0, input.buffer.subarray(input.cursor - recordLen, input.cursor));
18752
+ }
18745
18753
  ++topLevelCount;
18746
18754
  pushEntry({
18747
18755
  address: startElement2,
@@ -18831,7 +18839,10 @@ var StepParser = class extends StepHeaderParser {
18831
18839
  if (!charws(SEMICOLON)) {
18832
18840
  return syntaxError();
18833
18841
  }
18834
- onRecordIndexed?.(topLevelCount, expressID, foundItem);
18842
+ {
18843
+ const recordLen = input.address - startElement;
18844
+ onRecordIndexed?.(topLevelCount, expressID, foundItem, input.buffer.subarray(input.cursor - recordLen, input.cursor));
18845
+ }
18835
18846
  ++topLevelCount;
18836
18847
  pushEntry({
18837
18848
  address: startElement,
@@ -21645,6 +21656,35 @@ var StepModelBase = class {
21645
21656
  }
21646
21657
  this.bufferProvider_.unpinRange?.(this.address_[localID], this.length_[localID]);
21647
21658
  }
21659
+ /**
21660
+ * Drop captured source-window views on `localIDs` so the LRU can
21661
+ * evict those chunks. Vtables stay — `acquire` of the same
21662
+ * `(address, length)` is at a stable base. The next
21663
+ * `ensureResident` + field read rematerialises the view.
21664
+ *
21665
+ * @param localIDs Records whose `buffer` views to drop.
21666
+ */
21667
+ releaseSourceViews(localIDs) {
21668
+ if (!this.isSourceExternal) {
21669
+ return;
21670
+ }
21671
+ for (const localID of localIDs) {
21672
+ if (localID >= this.count_) {
21673
+ continue;
21674
+ }
21675
+ const item = this.complexEntries_?.get(localID) ?? this.descriptorCache_[localID];
21676
+ if (item === void 0) {
21677
+ continue;
21678
+ }
21679
+ item.buffer = void 0;
21680
+ if (item.multiMapping !== void 0) {
21681
+ for (const mapped of item.multiMapping) {
21682
+ mapped.buffer = void 0;
21683
+ }
21684
+ }
21685
+ }
21686
+ releaseScratchParsingBuffer();
21687
+ }
21648
21688
  /**
21649
21689
  * Unpin every local ID in `localIDs` (best-effort; missing IDs are
21650
21690
  * ignored). Use after {@link ensureResidentClosureByLocalID}, which
@@ -21675,6 +21715,17 @@ var StepModelBase = class {
21675
21715
  }
21676
21716
  return this.ensureResidentClosureByLocalID(localID, extraLocalIDs, seen);
21677
21717
  }
21718
+ /**
21719
+ * Express IDs referenced by a resident record (`#<id>` tokens in its
21720
+ * text, including multi-mapped class records). The record itself
21721
+ * must already be resident.
21722
+ *
21723
+ * @param localID The record to scan.
21724
+ * @return {number[]} Distinct referenced express IDs.
21725
+ */
21726
+ referencedExpressIDs(localID) {
21727
+ return this.scanRecordRefs_(localID);
21728
+ }
21678
21729
  /**
21679
21730
  * Scan a resident record's bytes for `#<expressID>` references.
21680
21731
  *
@@ -26860,6 +26911,38 @@ var StepEntityBase = class {
26860
26911
  }
26861
26912
  return value;
26862
26913
  }
26914
+ /**
26915
+ * Resolve a single reference field to its local ID without
26916
+ * constructing the target entity. Prep maps that only store
26917
+ * `Item.localID` (IfcStyledItem → faceset) must not hydrate the
26918
+ * target: on a windowed source that would pin the faceset record
26919
+ * (often megabytes) for every styled item at once.
26920
+ *
26921
+ * @param offset The offset in the vtable to extract from.
26922
+ * @param baseOffset The base offset of the class in the vtable.
26923
+ * @param depth The depth in the inheritance hierarchy.
26924
+ * @param optional Is this an optional field?
26925
+ * @return {number | null} The referenced local ID, or null if the
26926
+ * field is unset/optional-null.
26927
+ */
26928
+ extractReferenceLocalID(offset, baseOffset, depth, optional) {
26929
+ const [cursor, endCursor, buffer] = this.getOffsetAndEndCursor(offset, baseOffset, depth);
26930
+ const expressID = stepExtractReference(buffer, cursor, endCursor);
26931
+ if (expressID !== void 0) {
26932
+ return this.model.resolveExpressID(expressID) ?? null;
26933
+ }
26934
+ const inline = this.model.getInlineElementByAddress(extractInlineElementAddress(buffer, cursor, endCursor));
26935
+ if (inline !== void 0) {
26936
+ return inline.localID;
26937
+ }
26938
+ if (!optional) {
26939
+ throw new Error("Value in STEP was incorrectly typed");
26940
+ }
26941
+ if (!this.model.nullOnErrors && stepExtractOptional(buffer, cursor, endCursor) !== null) {
26942
+ throw new Error("Value in STEP was incorrectly typed");
26943
+ }
26944
+ return null;
26945
+ }
26863
26946
  /**
26864
26947
  *
26865
26948
  * @param buffer
@@ -27177,6 +27260,7 @@ var StepEntityBase = class {
27177
27260
  * @return {Uint8Array} The buffer for this.
27178
27261
  */
27179
27262
  get buffer() {
27263
+ this.guaranteeBuffer();
27180
27264
  return this.internalReference_.buffer;
27181
27265
  }
27182
27266
  /**
@@ -92297,8 +92381,9 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
92297
92381
  const styledItems = this.model.types(IfcStyledItem);
92298
92382
  for (const styledItem of styledItems) {
92299
92383
  try {
92300
- if (styledItem.Item !== null) {
92301
- this.materials.styledItemMap.set(styledItem.Item.localID, styledItem.localID);
92384
+ const itemLocalID = styledItem.extractReferenceLocalID(0, 0, 1, true);
92385
+ if (itemLocalID !== null) {
92386
+ this.materials.styledItemMap.set(itemLocalID, styledItem.localID);
92302
92387
  }
92303
92388
  } catch (ex) {
92304
92389
  this.handleMapPrepError_("IfcStyledItem", styledItem.expressID, ex);
@@ -92559,6 +92644,12 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
92559
92644
  * the relationship sweeps succeed on a windowed source. Call before
92560
92645
  * the first prepare on a model whose source is external.
92561
92646
  *
92647
+ * Pins the prep-type records themselves (and a 1-hop of product /
92648
+ * material records the relationship getters hydrate). Does **not**
92649
+ * BFS-pin styled-item Item closures — those are facesets, and
92650
+ * walking them here pulled most of the file into the windowed LRU
92651
+ * before the first product extract.
92652
+ *
92562
92653
  * @return {Promise<Set<number>>} Pinned local IDs — caller must
92563
92654
  * {@link StepModelBase.unpinLocalIDs} after prepare/extract.
92564
92655
  */
@@ -92567,17 +92658,48 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
92567
92658
  if (!this.model.isSourceExternal) {
92568
92659
  return pinned;
92569
92660
  }
92570
- const prepTypes = [
92571
- IfcProject,
92661
+ for (const type of [IfcProject, IfcMaterialDefinitionRepresentation]) {
92662
+ for (const expressID of this.model.expressIDsOfTypes(type)) {
92663
+ await this.model.ensureResidentClosureByExpressID(expressID, void 0, pinned);
92664
+ }
92665
+ }
92666
+ const recordOnlyTypes = [
92572
92667
  IfcRelAssociatesMaterial,
92573
- IfcMaterialDefinitionRepresentation,
92574
92668
  IfcRelVoidsElement,
92575
92669
  IfcStyledItem,
92576
92670
  IfcRelAggregates
92577
92671
  ];
92578
- for (const type of prepTypes) {
92672
+ for (const type of recordOnlyTypes) {
92579
92673
  for (const expressID of this.model.expressIDsOfTypes(type)) {
92580
- await this.model.ensureResidentClosureByExpressID(expressID, void 0, pinned);
92674
+ const localID = this.model.resolveExpressID(expressID);
92675
+ if (localID === void 0 || pinned.has(localID)) {
92676
+ continue;
92677
+ }
92678
+ await this.model.ensureResidentByLocalID(localID);
92679
+ this.model.pinByLocalID(localID);
92680
+ pinned.add(localID);
92681
+ }
92682
+ }
92683
+ const oneHopTypes = [
92684
+ IfcRelAssociatesMaterial,
92685
+ IfcRelVoidsElement,
92686
+ IfcRelAggregates
92687
+ ];
92688
+ for (const type of oneHopTypes) {
92689
+ for (const expressID of this.model.expressIDsOfTypes(type)) {
92690
+ const localID = this.model.resolveExpressID(expressID);
92691
+ if (localID === void 0) {
92692
+ continue;
92693
+ }
92694
+ for (const refExpressID of this.model.referencedExpressIDs(localID)) {
92695
+ const refLocalID = this.model.resolveExpressID(refExpressID);
92696
+ if (refLocalID === void 0 || pinned.has(refLocalID)) {
92697
+ continue;
92698
+ }
92699
+ await this.model.ensureResidentByLocalID(refLocalID);
92700
+ this.model.pinByLocalID(refLocalID);
92701
+ pinned.add(refLocalID);
92702
+ }
92581
92703
  }
92582
92704
  }
92583
92705
  return pinned;
@@ -93304,12 +93426,13 @@ function heapDeltaSuffix(state) {
93304
93426
  function formatStageLine(state, final) {
93305
93427
  const duration = state.lastElapsedMs - state.startElapsedMs;
93306
93428
  const heap = heapDeltaSuffix(state);
93429
+ const window2 = state.residentSourceMb !== void 0 ? `, window=${formatMb(state.residentSourceMb)} MB` : "";
93307
93430
  const determinate = state.percent !== void 0;
93308
93431
  if (final && !(determinate && state.percent < PERCENT)) {
93309
- return `${state.label}: ${formatSeconds(duration)}${heap}`;
93432
+ return `${state.label}: ${formatSeconds(duration)}${heap}${window2}`;
93310
93433
  }
93311
93434
  const bar = formatBar(determinate ? state.percent : void 0);
93312
- return `${state.label} ${bar} ${formatSeconds(duration)}${heap}`;
93435
+ return `${state.label} ${bar} ${formatSeconds(duration)}${heap}${window2}`;
93313
93436
  }
93314
93437
  var LoadLogAccumulator = class {
93315
93438
  constructor() {
@@ -93358,6 +93481,9 @@ var LoadLogAccumulator = class {
93358
93481
  current.startHeapMb ??= event.memoryMb;
93359
93482
  current.lastHeapMb = event.memoryMb;
93360
93483
  }
93484
+ if (event.residentSourceMb !== void 0) {
93485
+ current.residentSourceMb = event.residentSourceMb;
93486
+ }
93361
93487
  if (event.total !== void 0 && event.total > 0) {
93362
93488
  current.percent = event.completed / event.total * PERCENT;
93363
93489
  }
@@ -15943,7 +15943,7 @@ var ParsingBuffer = class {
15943
15943
  };
15944
15944
 
15945
15945
  // compiled/src/version/version.js
15946
- var versionString = "Conway v1.510.1439";
15946
+ var versionString = "Conway v1.512.1444";
15947
15947
 
15948
15948
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
15949
15949
  function pThreadsAllowed() {
@@ -18649,7 +18649,10 @@ var StepParser = class extends StepHeaderParser {
18649
18649
  if (!charws(SEMICOLON)) {
18650
18650
  return syntaxError();
18651
18651
  }
18652
- onRecordIndexed?.(topLevelCount, expressID, 0);
18652
+ {
18653
+ const recordLen = input.address - startElement2;
18654
+ onRecordIndexed?.(topLevelCount, expressID, 0, input.buffer.subarray(input.cursor - recordLen, input.cursor));
18655
+ }
18653
18656
  ++topLevelCount;
18654
18657
  pushEntry({
18655
18658
  address: startElement2,
@@ -18739,7 +18742,10 @@ var StepParser = class extends StepHeaderParser {
18739
18742
  if (!charws(SEMICOLON)) {
18740
18743
  return syntaxError();
18741
18744
  }
18742
- onRecordIndexed?.(topLevelCount, expressID, foundItem);
18745
+ {
18746
+ const recordLen = input.address - startElement;
18747
+ onRecordIndexed?.(topLevelCount, expressID, foundItem, input.buffer.subarray(input.cursor - recordLen, input.cursor));
18748
+ }
18743
18749
  ++topLevelCount;
18744
18750
  pushEntry({
18745
18751
  address: startElement,
@@ -21389,6 +21395,35 @@ var StepModelBase = class {
21389
21395
  }
21390
21396
  this.bufferProvider_.unpinRange?.(this.address_[localID], this.length_[localID]);
21391
21397
  }
21398
+ /**
21399
+ * Drop captured source-window views on `localIDs` so the LRU can
21400
+ * evict those chunks. Vtables stay — `acquire` of the same
21401
+ * `(address, length)` is at a stable base. The next
21402
+ * `ensureResident` + field read rematerialises the view.
21403
+ *
21404
+ * @param localIDs Records whose `buffer` views to drop.
21405
+ */
21406
+ releaseSourceViews(localIDs) {
21407
+ if (!this.isSourceExternal) {
21408
+ return;
21409
+ }
21410
+ for (const localID of localIDs) {
21411
+ if (localID >= this.count_) {
21412
+ continue;
21413
+ }
21414
+ const item = this.complexEntries_?.get(localID) ?? this.descriptorCache_[localID];
21415
+ if (item === void 0) {
21416
+ continue;
21417
+ }
21418
+ item.buffer = void 0;
21419
+ if (item.multiMapping !== void 0) {
21420
+ for (const mapped of item.multiMapping) {
21421
+ mapped.buffer = void 0;
21422
+ }
21423
+ }
21424
+ }
21425
+ releaseScratchParsingBuffer();
21426
+ }
21392
21427
  /**
21393
21428
  * Unpin every local ID in `localIDs` (best-effort; missing IDs are
21394
21429
  * ignored). Use after {@link ensureResidentClosureByLocalID}, which
@@ -21419,6 +21454,17 @@ var StepModelBase = class {
21419
21454
  }
21420
21455
  return this.ensureResidentClosureByLocalID(localID, extraLocalIDs, seen);
21421
21456
  }
21457
+ /**
21458
+ * Express IDs referenced by a resident record (`#<id>` tokens in its
21459
+ * text, including multi-mapped class records). The record itself
21460
+ * must already be resident.
21461
+ *
21462
+ * @param localID The record to scan.
21463
+ * @return {number[]} Distinct referenced express IDs.
21464
+ */
21465
+ referencedExpressIDs(localID) {
21466
+ return this.scanRecordRefs_(localID);
21467
+ }
21422
21468
  /**
21423
21469
  * Scan a resident record's bytes for `#<expressID>` references.
21424
21470
  *
@@ -22787,6 +22833,38 @@ var StepEntityBase = class {
22787
22833
  }
22788
22834
  return value;
22789
22835
  }
22836
+ /**
22837
+ * Resolve a single reference field to its local ID without
22838
+ * constructing the target entity. Prep maps that only store
22839
+ * `Item.localID` (IfcStyledItem → faceset) must not hydrate the
22840
+ * target: on a windowed source that would pin the faceset record
22841
+ * (often megabytes) for every styled item at once.
22842
+ *
22843
+ * @param offset The offset in the vtable to extract from.
22844
+ * @param baseOffset The base offset of the class in the vtable.
22845
+ * @param depth The depth in the inheritance hierarchy.
22846
+ * @param optional Is this an optional field?
22847
+ * @return {number | null} The referenced local ID, or null if the
22848
+ * field is unset/optional-null.
22849
+ */
22850
+ extractReferenceLocalID(offset, baseOffset, depth, optional) {
22851
+ const [cursor, endCursor, buffer] = this.getOffsetAndEndCursor(offset, baseOffset, depth);
22852
+ const expressID = stepExtractReference(buffer, cursor, endCursor);
22853
+ if (expressID !== void 0) {
22854
+ return this.model.resolveExpressID(expressID) ?? null;
22855
+ }
22856
+ const inline = this.model.getInlineElementByAddress(extractInlineElementAddress(buffer, cursor, endCursor));
22857
+ if (inline !== void 0) {
22858
+ return inline.localID;
22859
+ }
22860
+ if (!optional) {
22861
+ throw new Error("Value in STEP was incorrectly typed");
22862
+ }
22863
+ if (!this.model.nullOnErrors && stepExtractOptional(buffer, cursor, endCursor) !== null) {
22864
+ throw new Error("Value in STEP was incorrectly typed");
22865
+ }
22866
+ return null;
22867
+ }
22790
22868
  /**
22791
22869
  *
22792
22870
  * @param buffer
@@ -23104,6 +23182,7 @@ var StepEntityBase = class {
23104
23182
  * @return {Uint8Array} The buffer for this.
23105
23183
  */
23106
23184
  get buffer() {
23185
+ this.guaranteeBuffer();
23107
23186
  return this.internalReference_.buffer;
23108
23187
  }
23109
23188
  /**
@@ -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.510.1439";
947
+ var versionString = "Conway v1.512.1444";
948
948
 
949
949
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
950
950
  var wasmType = "";
@@ -3824,7 +3824,10 @@ var StepParser = class extends StepHeaderParser {
3824
3824
  if (!charws(SEMICOLON)) {
3825
3825
  return syntaxError();
3826
3826
  }
3827
- onRecordIndexed?.(topLevelCount, expressID, 0);
3827
+ {
3828
+ const recordLen = input.address - startElement2;
3829
+ onRecordIndexed?.(topLevelCount, expressID, 0, input.buffer.subarray(input.cursor - recordLen, input.cursor));
3830
+ }
3828
3831
  ++topLevelCount;
3829
3832
  pushEntry({
3830
3833
  address: startElement2,
@@ -3914,7 +3917,10 @@ var StepParser = class extends StepHeaderParser {
3914
3917
  if (!charws(SEMICOLON)) {
3915
3918
  return syntaxError();
3916
3919
  }
3917
- onRecordIndexed?.(topLevelCount, expressID, foundItem);
3920
+ {
3921
+ const recordLen = input.address - startElement;
3922
+ onRecordIndexed?.(topLevelCount, expressID, foundItem, input.buffer.subarray(input.cursor - recordLen, input.cursor));
3923
+ }
3918
3924
  ++topLevelCount;
3919
3925
  pushEntry({
3920
3926
  address: startElement,
@@ -5765,6 +5771,35 @@ var StepModelBase = class {
5765
5771
  }
5766
5772
  this.bufferProvider_.unpinRange?.(this.address_[localID], this.length_[localID]);
5767
5773
  }
5774
+ /**
5775
+ * Drop captured source-window views on `localIDs` so the LRU can
5776
+ * evict those chunks. Vtables stay — `acquire` of the same
5777
+ * `(address, length)` is at a stable base. The next
5778
+ * `ensureResident` + field read rematerialises the view.
5779
+ *
5780
+ * @param localIDs Records whose `buffer` views to drop.
5781
+ */
5782
+ releaseSourceViews(localIDs) {
5783
+ if (!this.isSourceExternal) {
5784
+ return;
5785
+ }
5786
+ for (const localID of localIDs) {
5787
+ if (localID >= this.count_) {
5788
+ continue;
5789
+ }
5790
+ const item = this.complexEntries_?.get(localID) ?? this.descriptorCache_[localID];
5791
+ if (item === void 0) {
5792
+ continue;
5793
+ }
5794
+ item.buffer = void 0;
5795
+ if (item.multiMapping !== void 0) {
5796
+ for (const mapped of item.multiMapping) {
5797
+ mapped.buffer = void 0;
5798
+ }
5799
+ }
5800
+ }
5801
+ releaseScratchParsingBuffer();
5802
+ }
5768
5803
  /**
5769
5804
  * Unpin every local ID in `localIDs` (best-effort; missing IDs are
5770
5805
  * ignored). Use after {@link ensureResidentClosureByLocalID}, which
@@ -5795,6 +5830,17 @@ var StepModelBase = class {
5795
5830
  }
5796
5831
  return this.ensureResidentClosureByLocalID(localID, extraLocalIDs, seen);
5797
5832
  }
5833
+ /**
5834
+ * Express IDs referenced by a resident record (`#<id>` tokens in its
5835
+ * text, including multi-mapped class records). The record itself
5836
+ * must already be resident.
5837
+ *
5838
+ * @param localID The record to scan.
5839
+ * @return {number[]} Distinct referenced express IDs.
5840
+ */
5841
+ referencedExpressIDs(localID) {
5842
+ return this.scanRecordRefs_(localID);
5843
+ }
5798
5844
  /**
5799
5845
  * Scan a resident record's bytes for `#<expressID>` references.
5800
5846
  *
@@ -10980,6 +11026,38 @@ var StepEntityBase = class {
10980
11026
  }
10981
11027
  return value;
10982
11028
  }
11029
+ /**
11030
+ * Resolve a single reference field to its local ID without
11031
+ * constructing the target entity. Prep maps that only store
11032
+ * `Item.localID` (IfcStyledItem → faceset) must not hydrate the
11033
+ * target: on a windowed source that would pin the faceset record
11034
+ * (often megabytes) for every styled item at once.
11035
+ *
11036
+ * @param offset The offset in the vtable to extract from.
11037
+ * @param baseOffset The base offset of the class in the vtable.
11038
+ * @param depth The depth in the inheritance hierarchy.
11039
+ * @param optional Is this an optional field?
11040
+ * @return {number | null} The referenced local ID, or null if the
11041
+ * field is unset/optional-null.
11042
+ */
11043
+ extractReferenceLocalID(offset, baseOffset, depth, optional) {
11044
+ const [cursor, endCursor, buffer] = this.getOffsetAndEndCursor(offset, baseOffset, depth);
11045
+ const expressID = stepExtractReference(buffer, cursor, endCursor);
11046
+ if (expressID !== void 0) {
11047
+ return this.model.resolveExpressID(expressID) ?? null;
11048
+ }
11049
+ const inline = this.model.getInlineElementByAddress(extractInlineElementAddress(buffer, cursor, endCursor));
11050
+ if (inline !== void 0) {
11051
+ return inline.localID;
11052
+ }
11053
+ if (!optional) {
11054
+ throw new Error("Value in STEP was incorrectly typed");
11055
+ }
11056
+ if (!this.model.nullOnErrors && stepExtractOptional(buffer, cursor, endCursor) !== null) {
11057
+ throw new Error("Value in STEP was incorrectly typed");
11058
+ }
11059
+ return null;
11060
+ }
10983
11061
  /**
10984
11062
  *
10985
11063
  * @param buffer
@@ -11297,6 +11375,7 @@ var StepEntityBase = class {
11297
11375
  * @return {Uint8Array} The buffer for this.
11298
11376
  */
11299
11377
  get buffer() {
11378
+ this.guaranteeBuffer();
11300
11379
  return this.internalReference_.buffer;
11301
11380
  }
11302
11381
  /**
@@ -253,8 +253,9 @@ export declare class IfcApiProxyIfc implements IfcApiModelPassthrough {
253
253
  /**
254
254
  * Windowed-from-birth twin of parseColumnarAndExtractAsync: the
255
255
  * source stays in `store`, parse windows are filled through it, and
256
- * the model never holds a resident copy. Preview-during-parse is
257
- * skipped (that channel needs a resident prefix). Deferred opens
256
+ * the model never holds a resident copy. The full prefix-extract
257
+ * preview channel is skipped (it needs a resident prefix); a sparse
258
+ * AABB imposter rides onRecordIndexed instead. Deferred opens
258
259
  * page prep closures before prepareDemandExtraction; non-deferred
259
260
  * opens drain the demand pump with per-product residency.
260
261
  *