@ifc-lite/geometry 7.6.0 → 7.8.1

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 (101) hide show
  1. package/README.md +64 -0
  2. package/dist/domain-export-call.d.ts +4 -0
  3. package/dist/domain-export-call.d.ts.map +1 -0
  4. package/dist/domain-export-call.js +19 -0
  5. package/dist/domain-export-call.js.map +1 -0
  6. package/dist/geometry-parallel-options.d.ts +15 -0
  7. package/dist/geometry-parallel-options.d.ts.map +1 -1
  8. package/dist/geometry-parallel.d.ts +2 -47
  9. package/dist/geometry-parallel.d.ts.map +1 -1
  10. package/dist/geometry-parallel.js +50 -146
  11. package/dist/geometry-parallel.js.map +1 -1
  12. package/dist/geometry-worker-pool.d.ts +72 -0
  13. package/dist/geometry-worker-pool.d.ts.map +1 -0
  14. package/dist/geometry-worker-pool.js +176 -0
  15. package/dist/geometry-worker-pool.js.map +1 -0
  16. package/dist/geometry.worker.d.ts.map +1 -1
  17. package/dist/geometry.worker.js +34 -36
  18. package/dist/geometry.worker.js.map +1 -1
  19. package/dist/huge-file-error.d.ts +1 -2
  20. package/dist/huge-file-error.d.ts.map +1 -1
  21. package/dist/huge-file-error.js +4 -5
  22. package/dist/huge-file-error.js.map +1 -1
  23. package/dist/hung-job-recovery.d.ts +26 -2
  24. package/dist/hung-job-recovery.d.ts.map +1 -1
  25. package/dist/hung-job-recovery.js +42 -7
  26. package/dist/hung-job-recovery.js.map +1 -1
  27. package/dist/ifc-lite-bridge.d.ts +2 -0
  28. package/dist/ifc-lite-bridge.d.ts.map +1 -1
  29. package/dist/ifc-lite-bridge.js +19 -35
  30. package/dist/ifc-lite-bridge.js.map +1 -1
  31. package/dist/in-call-heartbeat.d.ts +20 -0
  32. package/dist/in-call-heartbeat.d.ts.map +1 -0
  33. package/dist/in-call-heartbeat.js +39 -0
  34. package/dist/in-call-heartbeat.js.map +1 -0
  35. package/dist/index.d.ts +9 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +15 -30
  38. package/dist/index.js.map +1 -1
  39. package/dist/main-engine-init.d.ts +5 -0
  40. package/dist/main-engine-init.d.ts.map +1 -0
  41. package/dist/main-engine-init.js +42 -0
  42. package/dist/main-engine-init.js.map +1 -0
  43. package/dist/map-normalization-capability.d.ts +7 -0
  44. package/dist/map-normalization-capability.d.ts.map +1 -0
  45. package/dist/map-normalization-capability.js +32 -0
  46. package/dist/map-normalization-capability.js.map +1 -0
  47. package/dist/native-bridge.d.ts +1 -0
  48. package/dist/native-bridge.d.ts.map +1 -1
  49. package/dist/native-bridge.js +1 -0
  50. package/dist/native-bridge.js.map +1 -1
  51. package/dist/perf-flags.d.ts +55 -0
  52. package/dist/perf-flags.d.ts.map +1 -0
  53. package/dist/perf-flags.js +66 -0
  54. package/dist/perf-flags.js.map +1 -0
  55. package/dist/platform-bridge.d.ts +2 -0
  56. package/dist/platform-bridge.d.ts.map +1 -1
  57. package/dist/platform-bridge.js.map +1 -1
  58. package/dist/prepass-routing.d.ts +53 -0
  59. package/dist/prepass-routing.d.ts.map +1 -0
  60. package/dist/prepass-routing.js +100 -0
  61. package/dist/prepass-routing.js.map +1 -0
  62. package/dist/remesh/remesh-client.d.ts.map +1 -1
  63. package/dist/remesh/remesh-client.js +5 -1
  64. package/dist/remesh/remesh-client.js.map +1 -1
  65. package/dist/remesh/remesh-core.d.ts.map +1 -1
  66. package/dist/remesh/remesh-core.js +29 -11
  67. package/dist/remesh/remesh-core.js.map +1 -1
  68. package/dist/remesh/remesh-protocol.d.ts +10 -4
  69. package/dist/remesh/remesh-protocol.d.ts.map +1 -1
  70. package/dist/remesh/remesh-protocol.js.map +1 -1
  71. package/dist/remesh/remesh.worker.js +25 -10
  72. package/dist/remesh/remesh.worker.js.map +1 -1
  73. package/dist/scan-proposals.d.ts +132 -0
  74. package/dist/scan-proposals.d.ts.map +1 -0
  75. package/dist/scan-proposals.js +12 -0
  76. package/dist/scan-proposals.js.map +1 -0
  77. package/dist/scan-segmentation.d.ts +205 -0
  78. package/dist/scan-segmentation.d.ts.map +1 -0
  79. package/dist/scan-segmentation.js +17 -0
  80. package/dist/scan-segmentation.js.map +1 -0
  81. package/dist/warm-pool.d.ts +27 -0
  82. package/dist/warm-pool.d.ts.map +1 -0
  83. package/dist/warm-pool.js +48 -0
  84. package/dist/warm-pool.js.map +1 -0
  85. package/dist/wasm-shared-module.d.ts +17 -19
  86. package/dist/wasm-shared-module.d.ts.map +1 -1
  87. package/dist/wasm-shared-module.js +90 -77
  88. package/dist/wasm-shared-module.js.map +1 -1
  89. package/dist/wasm-streaming-guard.d.ts +2 -0
  90. package/dist/wasm-streaming-guard.d.ts.map +1 -0
  91. package/dist/wasm-streaming-guard.js +22 -0
  92. package/dist/wasm-streaming-guard.js.map +1 -0
  93. package/dist/worker-count.d.ts +10 -0
  94. package/dist/worker-count.d.ts.map +1 -1
  95. package/dist/worker-count.js +19 -0
  96. package/dist/worker-count.js.map +1 -1
  97. package/dist/worker-trace.d.ts +16 -0
  98. package/dist/worker-trace.d.ts.map +1 -0
  99. package/dist/worker-trace.js +39 -0
  100. package/dist/worker-trace.js.map +1 -0
  101. package/package.json +17 -6
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Typed entry to plane and cylinder detection in point clouds (#6870, #6893). The algorithm is
3
+ * Rust (`ifc_lite_processing::scan_segmentation`); this module only frames
4
+ * the input and types the JSON report the wasm call returns.
5
+ *
6
+ * Coordinates are metres in the frame of the supplied positions, plus
7
+ * `options.origin` on output. The viewer's retained reservoir sample is Y-up
8
+ * and decode-relative: pass `upAxis: [0, 1, 0]`.
9
+ */
10
+ import type { IfcAPI } from '@ifc-lite/wasm';
11
+ export type ScanVec3 = [number, number, number];
12
+ /** Axis-aligned crop box in the positions' frame (inclusive). */
13
+ export interface ScanRegion {
14
+ min: ScanVec3;
15
+ max: ScanVec3;
16
+ }
17
+ /** Every field is optional; omitted fields take the Rust defaults below. */
18
+ export interface ScanSegmentationOptions {
19
+ /** Averaging voxel edge. Default 0.03 m; 0.005..=1. */
20
+ voxelSizeMetres?: number;
21
+ /**
22
+ * Voxel budget; past it the voxel size doubles. Default 1,500,000. Memory
23
+ * is roughly 180 bytes per voxel: the 8,000,000 maximum (with 2 normal
24
+ * rings) peaks near 1.4 GB, more than a browser tab should spend.
25
+ */
26
+ maxVoxels?: number;
27
+ /** Normal neighbourhood: 1 = 26 neighbours (default), 2 = 124. */
28
+ normalNeighborRings?: number;
29
+ /** Occupied voxels (self included) a normal needs. Default 6. */
30
+ minNeighbors?: number;
31
+ /**
32
+ * Seed voxels have curvature at most this, or at most the curvature of the
33
+ * flattest 5 % of voxels when noise lifts even flat surfaces above it.
34
+ * Default 0.02.
35
+ */
36
+ maxSeedCurvature?: number;
37
+ /** Growth and merge angle tolerance. Default 10 degrees. */
38
+ maxNormalAngleDegrees?: number;
39
+ /** Growth and merge distance tolerance. Default 0.02 m. */
40
+ maxPlaneDistanceMetres?: number;
41
+ /** Robust refit band in MADs. Default 2.5. */
42
+ madScale?: number;
43
+ /** Regions whose normals turn faster than this (1/radius) are curved. Default 1 per metre. */
44
+ maxBendPerMetre?: number;
45
+ /** Smaller planes are dropped. Default 0.25 m^2. */
46
+ minPlaneAreaSquareMetres?: number;
47
+ /** Horizontal / vertical classification tolerance. Default 10 degrees. */
48
+ classificationAngleDegrees?: number;
49
+ /** Up direction of the positions' frame. Default [0, 0, 1]. */
50
+ upAxis?: ScanVec3;
51
+ /** When given, every plane normal faces the scanner. */
52
+ scannerPosition?: ScanVec3 | null;
53
+ /** Added to every output coordinate. Default [0, 0, 0]. */
54
+ origin?: ScanVec3;
55
+ /** Only points inside this box take part. */
56
+ region?: ScanRegion | null;
57
+ /** Largest planes kept. Default 10,000. */
58
+ maxPlanes?: number;
59
+ /** Look for cylinders (columns, pipes) among non-planar voxels. Default true. */
60
+ detectCylinders?: boolean;
61
+ /** Accepted cylinder radius range. The minimum defaults to two voxel edges (null), the maximum to 2 m. */
62
+ minCylinderRadiusMetres?: number | null;
63
+ maxCylinderRadiusMetres?: number;
64
+ /** Share of a group a candidate must fit. Default 0.6. */
65
+ minCylinderInlierFraction?: number;
66
+ /** Minimum circumference covered. Default 90 degrees. */
67
+ minCylinderArcDegrees?: number;
68
+ /** Minimum length along the axis. Default 0.3 m. */
69
+ minCylinderLengthMetres?: number;
70
+ /** RANSAC draws per candidate. Default 256. */
71
+ cylinderDraws?: number;
72
+ /** Voxels each draw is scored on. Default 2,048. */
73
+ cylinderScoreSample?: number;
74
+ /** Largest non-planar groups examined. Default 1,024. */
75
+ maxCylinderGroups?: number;
76
+ }
77
+ export type ScanPlaneOrientation = 'horizontal' | 'vertical' | 'sloped';
78
+ /** `scanner`: the normal faces `scannerPosition`. `canonical`: horizontal planes face up, others a fixed axis sign. */
79
+ export type ScanNormalSource = 'scanner' | 'canonical';
80
+ export interface ScanPlaneExtent {
81
+ center: ScanVec3;
82
+ uAxis: ScanVec3;
83
+ vAxis: ScanVec3;
84
+ uLength: number;
85
+ vLength: number;
86
+ corners: [ScanVec3, ScanVec3, ScanVec3, ScanVec3];
87
+ }
88
+ export interface ScanPlane {
89
+ /** Unit normal; `normal . x + d = 0`. */
90
+ normal: ScanVec3;
91
+ d: number;
92
+ centroid: ScanVec3;
93
+ inlierPoints: number;
94
+ inlierVoxels: number;
95
+ areaSquareMetres: number;
96
+ rmsMetres: number;
97
+ extent: ScanPlaneExtent;
98
+ orientation: ScanPlaneOrientation;
99
+ normalSource: ScanNormalSource;
100
+ }
101
+ /** Axis relative to `upAxis`: vertical is a column, horizontal a pipe or beam. */
102
+ export type ScanAxisOrientation = 'vertical' | 'horizontal' | 'sloped';
103
+ /** The faces of a polygonal column: a regular polygon of `faces` sides about the axis. */
104
+ export interface ScanFacets {
105
+ /** Sides of the whole polygon (6 or more), seen or not. */
106
+ faces: number;
107
+ /**
108
+ * Unit outward normal of one face, across the axis; the others follow at
109
+ * multiples of 360 / `faces` degrees. The face nearest the frame's +x
110
+ * (+y when the axis runs along x).
111
+ */
112
+ faceNormal: ScanVec3;
113
+ /** Distance from the axis to each face (inradius). */
114
+ apothem: number;
115
+ }
116
+ export interface ScanCylinder {
117
+ axisStart: ScanVec3;
118
+ axisEnd: ScanVec3;
119
+ /** Unit; points up unless horizontal. */
120
+ axisDirection: ScanVec3;
121
+ /** For a faceted column, the circumradius (axis to corner). */
122
+ radius: number;
123
+ length: number;
124
+ /** Lowest and highest axis end along `upAxis`. */
125
+ heightRange: [number, number];
126
+ /** Circumference covered by the inliers, in degrees; for pieces joined across a density gap, the larger piece's arc (a lower bound). */
127
+ arcDegrees: number;
128
+ inlierPoints: number;
129
+ inlierVoxels: number;
130
+ rmsMetres: number;
131
+ orientation: ScanAxisOrientation;
132
+ /** Set for a polygonal column (a ring of six or more flat faces); null when round. */
133
+ faceted: ScanFacets | null;
134
+ }
135
+ export interface ScanSegmentationStats {
136
+ inputPoints: number;
137
+ acceptedPoints: number;
138
+ rejectedPoints: number;
139
+ outsideRegionPoints: number;
140
+ /** f32 spacing at the largest coordinate: the finest resolution the positions carry. */
141
+ coordinateSpacingMetres: number;
142
+ voxelSizeMetres: number;
143
+ coarsenings: number;
144
+ voxels: number;
145
+ voxelsWithNormals: number;
146
+ seedVoxels: number;
147
+ /** The curvature gate the seeds passed: `maxSeedCurvature`, or higher on noisy data. */
148
+ seedCurvature: number;
149
+ regionsGrown: number;
150
+ regionsMerged: number;
151
+ curvedRegionsRejected: number;
152
+ smallRegionsRejected: number;
153
+ planarVoxels: number;
154
+ cylinderGroups: number;
155
+ cylindersRejectedAsSpheres: number;
156
+ cylinderCandidatesBelowShare: number;
157
+ cylinderRefitsFailed: number;
158
+ cylindersRejectedForRadius: number;
159
+ cylindersRejectedAsSparse: number;
160
+ cylindersRejectedAsFacets: number;
161
+ cylindersRejectedAsPierced: number;
162
+ cylindersRejectedForUnevenArc: number;
163
+ cylindersRejectedAsDuplicates: number;
164
+ cylindersJoinedAcrossGaps: number;
165
+ cylindersRejectedForArc: number;
166
+ cylindersRejectedForLength: number;
167
+ /** Rings of adjacent vertical planes about a common axis, examined as wide or polygonal columns. */
168
+ planeRings: number;
169
+ /** Rings neither round nor a regular polygon of six or more faces: they stay planes. */
170
+ planeRingsRejectedAsIrregular: number;
171
+ /** Rings with scanned surface inside their footprint (a bay or niche seen from the room). */
172
+ planeRingsRejectedAsHollow: number;
173
+ /** Planes removed because they lie on a reported cylinder or are a faceted column's faces. */
174
+ planesAbsorbedIntoCylinders: number;
175
+ }
176
+ /** Which bounds acted; a bound that acts is always reported. */
177
+ export interface ScanSegmentationLimits {
178
+ voxelBudgetCoarsened: boolean;
179
+ planeLimitHit: boolean;
180
+ /** Positions too far from their frame origin for the voxel size; pass a local `origin`. */
181
+ coordinatePrecisionDegraded: boolean;
182
+ cylinderGroupLimitHit: boolean;
183
+ }
184
+ export interface ScanSegmentationReport {
185
+ algorithm: string;
186
+ /** Largest area first. A surface reported as a cylinder is not also a plane. */
187
+ planes: ScanPlane[];
188
+ /** Longest first; round and faceted columns, pipes. */
189
+ cylinders: ScanCylinder[];
190
+ stats: ScanSegmentationStats;
191
+ limits: ScanSegmentationLimits;
192
+ }
193
+ /**
194
+ * xyz positions; `count` limits them to a prefix, so a reservoir whose buffer
195
+ * is larger than its fill (the viewer's retained scan sample) passes as is.
196
+ */
197
+ export interface ScanPointInput {
198
+ positions: Float32Array;
199
+ count?: number;
200
+ }
201
+ /** The wasm surface this needs: an initialised `IfcAPI` satisfies it. */
202
+ export type ScanSegmentationEngine = Pick<IfcAPI, 'segmentScanPoints'>;
203
+ /** Detect planes and cylinders in `input`. Throws the Rust error message on invalid options. */
204
+ export declare function segmentScan(engine: ScanSegmentationEngine, input: ScanPointInput, options?: ScanSegmentationOptions): ScanSegmentationReport;
205
+ //# sourceMappingURL=scan-segmentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-segmentation.d.ts","sourceRoot":"","sources":["../src/scan-segmentation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /** Detect planes and cylinders in `input`. Throws the Rust error message on invalid options. */
5
+ export function segmentScan(engine, input, options = {}) {
6
+ const available = Math.floor(input.positions.length / 3);
7
+ const count = input.count ?? available;
8
+ if (!Number.isInteger(count) || count < 0 || count > available) {
9
+ throw new RangeError(`Scan point count ${count} must be an integer within 0..${available}`);
10
+ }
11
+ const positions = count === available && input.positions.length === count * 3
12
+ ? input.positions
13
+ : input.positions.subarray(0, count * 3);
14
+ const bytes = engine.segmentScanPoints(positions, JSON.stringify(options));
15
+ return JSON.parse(new TextDecoder().decode(bytes));
16
+ }
17
+ //# sourceMappingURL=scan-segmentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-segmentation.js","sourceRoot":"","sources":["../src/scan-segmentation.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AA2N/D,gGAAgG;AAChG,MAAM,UAAU,WAAW,CACzB,MAA8B,EAC9B,KAAqB,EACrB,UAAmC,EAAE;IAErC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;QAC/D,MAAM,IAAI,UAAU,CAAC,oBAAoB,KAAK,iCAAiC,SAAS,EAAE,CAAC,CAAC;IAC9F,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,KAAK,KAAK,GAAG,CAAC;QAC3E,CAAC,CAAC,KAAK,CAAC,SAAS;QACjB,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3E,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAA2B,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The realm's one pool of prewarmed geometry workers (#7036) and the calls a
3
+ * host uses to fill and empty it. Behind the `warmPool` perf flag: with the
4
+ * experiment disabled, `getWarmGeometryWorkerPool()` is null, nothing is prewarmed
5
+ * and every load spawns its own workers exactly as before.
6
+ */
7
+ import { GeometryWorkerPool, type GeometryWorkerPoolStats } from './geometry-worker-pool.js';
8
+ /** The shared pool, or null when the flag is off or the realm has no workers. */
9
+ export declare function getWarmGeometryWorkerPool(): GeometryWorkerPool | null;
10
+ /**
11
+ * Fill the pool with the workers a parallel load of `fileSizeMB` will use (its
12
+ * geometry workers plus the pre-pass worker), each with the engine
13
+ * instantiated from the shared compiled module. Call it as soon as a load is
14
+ * requested, so the spawn overlaps the file read. Resolves to the number of
15
+ * workers started (0 when the pool is off, already holds them, or the module
16
+ * could not be compiled: the load then spawns as before).
17
+ */
18
+ export declare function prewarmGeometryWorkers(options?: {
19
+ fileSizeMB?: number;
20
+ workerCountOverride?: number;
21
+ wasmUrl?: string;
22
+ }): Promise<number>;
23
+ /** Terminate every idle prewarmed worker (memory pressure, a hidden tab, a resource-limit retry). */
24
+ export declare function releaseWarmGeometryWorkers(reason?: string): number;
25
+ /** Idle-pool counters for `?perfMem=1` and the benchmark guards; null before the pool exists. */
26
+ export declare function warmGeometryWorkerPoolStats(): GeometryWorkerPoolStats | null;
27
+ //# sourceMappingURL=warm-pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warm-pool.d.ts","sourceRoot":"","sources":["../src/warm-pool.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAQ7F,iFAAiF;AACjF,wBAAgB,yBAAyB,IAAI,kBAAkB,GAAG,IAAI,CAGrE;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACpF,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED,qGAAqG;AACrG,wBAAgB,0BAA0B,CAAC,MAAM,SAAY,GAAG,MAAM,CAErE;AAED,iGAAiG;AACjG,wBAAgB,2BAA2B,IAAI,uBAAuB,GAAG,IAAI,CAE5E"}
@@ -0,0 +1,48 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * The realm's one pool of prewarmed geometry workers (#7036) and the calls a
6
+ * host uses to fill and empty it. Behind the `warmPool` perf flag: with the
7
+ * experiment disabled, `getWarmGeometryWorkerPool()` is null, nothing is prewarmed
8
+ * and every load spawns its own workers exactly as before.
9
+ */
10
+ import { GeometryWorkerPool } from './geometry-worker-pool.js';
11
+ import { postGeometryWorkerInit } from './geometry-worker-init.js';
12
+ import { readWarmPoolFlag } from './perf-flags.js';
13
+ import { compileSharedWasmModule } from './wasm-shared-module.js';
14
+ import { planLoadWorkerCount } from './worker-count.js';
15
+ let shared = null;
16
+ /** The shared pool, or null when the flag is off or the realm has no workers. */
17
+ export function getWarmGeometryWorkerPool() {
18
+ if (typeof Worker === 'undefined' || !readWarmPoolFlag())
19
+ return null;
20
+ return (shared ??= new GeometryWorkerPool());
21
+ }
22
+ /**
23
+ * Fill the pool with the workers a parallel load of `fileSizeMB` will use (its
24
+ * geometry workers plus the pre-pass worker), each with the engine
25
+ * instantiated from the shared compiled module. Call it as soon as a load is
26
+ * requested, so the spawn overlaps the file read. Resolves to the number of
27
+ * workers started (0 when the pool is off, already holds them, or the module
28
+ * could not be compiled: the load then spawns as before).
29
+ */
30
+ export async function prewarmGeometryWorkers(options = {}) {
31
+ const pool = getWarmGeometryWorkerPool();
32
+ if (!pool)
33
+ return 0;
34
+ const module = await compileSharedWasmModule(options.wasmUrl);
35
+ if (!module)
36
+ return 0;
37
+ const { count } = planLoadWorkerCount(options.fileSizeMB ?? 8, options.workerCountOverride);
38
+ return pool.prewarm(count + 1, options.wasmUrl ?? '', (worker) => postGeometryWorkerInit(worker, undefined, module));
39
+ }
40
+ /** Terminate every idle prewarmed worker (memory pressure, a hidden tab, a resource-limit retry). */
41
+ export function releaseWarmGeometryWorkers(reason = 'release') {
42
+ return shared?.drain(reason) ?? 0;
43
+ }
44
+ /** Idle-pool counters for `?perfMem=1` and the benchmark guards; null before the pool exists. */
45
+ export function warmGeometryWorkerPoolStats() {
46
+ return shared?.stats() ?? null;
47
+ }
48
+ //# sourceMappingURL=warm-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warm-pool.js","sourceRoot":"","sources":["../src/warm-pool.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAgC,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,IAAI,MAAM,GAA8B,IAAI,CAAC;AAE7C,iFAAiF;AACjF,MAAM,UAAU,yBAAyB;IACvC,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,gBAAgB,EAAE;QAAE,OAAO,IAAI,CAAC;IACtE,OAAO,CAAC,MAAM,KAAK,IAAI,kBAAkB,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,UAAmF,EAAE;IAErF,MAAM,IAAI,GAAG,yBAAyB,EAAE,CAAC;IACzC,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,CAAC;IACpB,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9D,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC;IACtB,MAAM,EAAE,KAAK,EAAE,GAAG,mBAAmB,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC5F,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AACvH,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,0BAA0B,CAAC,MAAM,GAAG,SAAS;IAC3D,OAAO,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,2BAA2B;IACzC,OAAO,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC;AACjC,CAAC"}
@@ -1,26 +1,23 @@
1
1
  /**
2
- * Compile (or join the in-flight compile of) the engine binary for `explicitUrl`
3
- * — or the default resolution when omitted.
4
- *
5
- * Resolves to `null` — the caller then leaves the consumer on its own `init()` —
6
- * when the URL can't be resolved or compilation fails, so non-Vite consumers and
7
- * offline/edge failures degrade to the previous behaviour rather than breaking.
2
+ * Compile or join the engine binary. The pool's optional contract stays null on
3
+ * failure; the memo itself preserves rejection for the main loader's retry.
8
4
  */
9
5
  export declare function compileSharedWasmModule(explicitUrl?: string): Promise<WebAssembly.Module | null>;
6
+ /** Modern public init options; deliberately not a package-root export. */
7
+ type SharedWasmInitOptions = {
8
+ module_or_path: WebAssembly.Module | Promise<WebAssembly.Module>;
9
+ };
10
10
  /**
11
- * The compiled module for `explicitUrl` **only if a compile was already started**
12
- * for it — otherwise `null`, without starting one.
13
- *
14
- * This is the "join, don't initiate" accessor for consumers that have their own
15
- * working init path (`IfcLiteBridge.init()`): when a prewarm or a parallel load
16
- * has already fetched the binary, reuse it; when nothing has, do exactly what
17
- * this consumer did before rather than speculatively pulling 1.3 MB on a path
18
- * that may not need it.
11
+ * Prepare main init without starting a bundled fetch. Generated public init
12
+ * returns an already initialized engine BEFORE reading module_or_path. A cold
13
+ * loader reads this getter and starts/joins the strict memo inside its retry.
19
14
  *
20
- * Awaits an in-flight compile rather than racing it with a second fetch — the
21
- * bytes are the same and already on the wire.
15
+ * Raw sibling URLs do not prove the installed npm asset location. Only join an
16
+ * existing optional memo there, then give the loader concrete options or no
17
+ * options. Promise<undefined> would bypass the loader's default URL selection.
18
+ * The second URL constructor uses a parameter so bundlers leave it untouched.
22
19
  */
23
- export declare function getStartedSharedWasmModule(explicitUrl?: string): Promise<WebAssembly.Module | null> | null;
20
+ export declare function prepareSharedWasmInit(resolvedUrl?: string | URL | null, moduleUrl?: string): Promise<SharedWasmInitOptions | undefined>;
24
21
  /**
25
22
  * Start the shared fetch+compile BEFORE a file is opened, so the binary is
26
23
  * already downloaded and compiled by the time a load wants it.
@@ -30,7 +27,7 @@ export declare function getStartedSharedWasmModule(explicitUrl?: string): Promis
30
27
  * slow link the whole download sits in front of first geometry (measured 2.5 s
31
28
  * on a ~4 Mbit connection, for a 225 KB model).
32
29
  *
33
- * Fire-and-forget by design: a prewarm failure must never surface to the user or
30
+ * Fire-and-forget by design (the returned promise never rejects): a prewarm failure must never surface to the user or
34
31
  * poison the load path. `compileSharedWasmModule` already evicts a failed URL so
35
32
  * the real load retries, and every consumer falls back to its own `init()` when
36
33
  * no shared module is available. Callers decide *when* to call this (idle,
@@ -41,5 +38,6 @@ export declare function getStartedSharedWasmModule(explicitUrl?: string): Promis
41
38
  * Vite/webpack consumers (the viewer included) pass none and share the default
42
39
  * resolution, which is the intended usage.
43
40
  */
44
- export declare function prewarmSharedWasmModule(wasmUrl?: string): void;
41
+ export declare function prewarmSharedWasmModule(wasmUrl?: string): Promise<boolean>;
42
+ export {};
45
43
  //# sourceMappingURL=wasm-shared-module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wasm-shared-module.d.ts","sourceRoot":"","sources":["../src/wasm-shared-module.ts"],"names":[],"mappings":"AAoDA;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,IAAI,CAAC,CAgDpC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAK3C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAM9D"}
1
+ {"version":3,"file":"wasm-shared-module.d.ts","sourceRoot":"","sources":["../src/wasm-shared-module.ts"],"names":[],"mappings":"AA6GA;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,IAAI,CAAC,CAIhG;AAED,0EAA0E;AAC1E,KAAK,qBAAqB,GAAG;IAC3B,cAAc,EAAE,WAAW,CAAC,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;CAClE,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,GAAE,MAAM,GAAG,GAAG,GAAG,IAAuB,EACnD,SAAS,GAAE,MAAwB,GAClC,OAAO,CAAC,qBAAqB,GAAG,SAAS,CAAC,CAa5C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAS1E"}
@@ -17,8 +17,9 @@
17
17
  *
18
18
  * Keeping the memo here — rather than private to the worker pool — means the
19
19
  * second path can reuse whatever the first already compiled, so the binary is
20
- * fetched at most once per URL per realm no matter which path runs first. That
21
- * matters most when the two overlap: a prewarm started at page load and a small
20
+ * shared on pool-first and bundled main-init-first loads. Unbundled main init
21
+ * keeps wasm-bindgen's own asset resolution. Sharing matters most when
22
+ * the two overlap: a prewarm started at page load and a small
22
23
  * file opened seconds later would otherwise be two concurrent downloads of the
23
24
  * same 1.3 MB (browsers are not required to coalesce in-flight requests for the
24
25
  * same URL), on exactly the slow connections the prewarm exists to help.
@@ -48,88 +49,97 @@ function resolveWasmUrl(explicitUrl) {
48
49
  return null;
49
50
  }
50
51
  }
51
- /**
52
- * Compile (or join the in-flight compile of) the engine binary for `explicitUrl`
53
- * — or the default resolution when omitted.
54
- *
55
- * Resolves to `null` — the caller then leaves the consumer on its own `init()` —
56
- * when the URL can't be resolved or compilation fails, so non-Vite consumers and
57
- * offline/edge failures degrade to the previous behaviour rather than breaking.
58
- */
59
- export async function compileSharedWasmModule(explicitUrl) {
60
- if (typeof WebAssembly === 'undefined')
61
- return null;
62
- const url = resolveWasmUrl(explicitUrl);
63
- if (!url)
64
- return null;
65
- const cacheKey = url instanceof URL ? url.href : url;
66
- const cached = sharedWasmModulePromises.get(cacheKey);
52
+ // Match wasm-bindgen's public loader: a successful ordinary response with the
53
+ // wrong MIME type may use its bytes; transport/validation failures retain their
54
+ // original rejection. In particular, invalid application/wasm is not retried.
55
+ function permitsMimeFallback(response) {
56
+ return response.ok
57
+ && ['basic', 'cors', 'default'].includes(response.type)
58
+ && response.headers.get('Content-Type') !== 'application/wasm';
59
+ }
60
+ function acquireModule(url) {
61
+ const key = url instanceof URL ? url.href : url;
62
+ const cached = sharedWasmModulePromises.get(key);
67
63
  if (cached)
68
64
  return cached;
69
- const p = (async () => {
70
- try {
71
- if (typeof WebAssembly.compileStreaming === 'function') {
72
- try {
73
- // Compile WHILE the binary downloads (one streaming fetch + compile
74
- // for every consumer).
75
- return await WebAssembly.compileStreaming(fetch(url));
76
- }
77
- catch (err) {
78
- // Some static hosts serve `.wasm` with the wrong MIME type, which
79
- // rejects compileStreaming — fall through to the buffer path.
80
- //
81
- // Worth a line even though the fallback works: the streaming fetch is
82
- // already spent, so the buffer path downloads the ~1.3 MB binary a
83
- // SECOND time, and nothing else reports that. Once per URL per realm
84
- // (this runs inside the single-flight memo).
85
- console.warn('[stream] wasm compileStreaming rejected; refetching for the buffer path:', err);
86
- }
65
+ const promise = (async () => {
66
+ const response = await fetch(url);
67
+ if (typeof WebAssembly.compileStreaming !== 'function') {
68
+ // Preserve the optional helper's HTTP refusal even when its streaming API
69
+ // is absent. Main init must not accept bytes a present public streaming
70
+ // loader would reject. This is stricter than glue with both APIs absent.
71
+ if (!response.ok)
72
+ throw new TypeError('WebAssembly HTTP status code is not ok');
73
+ if (!['basic', 'cors', 'default'].includes(response.type)) {
74
+ throw new TypeError('WebAssembly response type is not supported');
87
75
  }
88
- const resp = await fetch(url);
89
- if (!resp.ok)
90
- return null;
91
- return await WebAssembly.compile(await resp.arrayBuffer());
76
+ return WebAssembly.compile(await response.arrayBuffer());
77
+ }
78
+ // Like generated init, permitted MIME rejection leaves the original body
79
+ // available for arrayBuffer. Do not tee/clone or fetch the binary again.
80
+ try {
81
+ return await WebAssembly.compileStreaming(response);
92
82
  }
93
- catch (err) {
94
- console.warn('[stream] shared wasm compile failed; consumers will self-init:', err);
95
- return null;
83
+ catch (error) {
84
+ if (!permitsMimeFallback(response))
85
+ throw error;
86
+ console.warn('[stream] wasm compileStreaming rejected MIME; using the same response bytes:', error);
87
+ return WebAssembly.compile(await response.arrayBuffer());
96
88
  }
97
- })();
98
- sharedWasmModulePromises.set(cacheKey, p);
99
- const result = await p;
100
- // Don't cache a failure — evict ONLY this URL's entry so the next load retries
101
- // (a transient fetch error shouldn't permanently disable the shared-module fast
102
- // path for the session), while other URLs' successful modules stay cached.
103
- //
104
- // Evict only if THIS promise is still the installed one. A failed compile can
105
- // have several awaiters; the first to resume evicts and a retry may install a
106
- // fresh promise before the rest resume. Without the identity check those late
107
- // awaiters would delete the *replacement*, breaking single-flight and letting
108
- // a second compile of the same binary start.
109
- if (result === null && sharedWasmModulePromises.get(cacheKey) === p) {
110
- sharedWasmModulePromises.delete(cacheKey);
111
- }
112
- return result;
89
+ })().catch((error) => {
90
+ // Evict the owner, not a replacement installed by a later load. All joining
91
+ // callers see the original rejection; the bridge's retry can start anew.
92
+ if (sharedWasmModulePromises.get(key) === promise)
93
+ sharedWasmModulePromises.delete(key);
94
+ throw error;
95
+ });
96
+ sharedWasmModulePromises.set(key, promise);
97
+ return promise;
98
+ }
99
+ const warnedFailures = new WeakSet();
100
+ function optionalModule(promise) {
101
+ return promise.catch((error) => {
102
+ if (!warnedFailures.has(promise)) {
103
+ warnedFailures.add(promise);
104
+ console.warn('[stream] shared wasm compile failed; consumers will self-init:', error);
105
+ }
106
+ return null;
107
+ });
113
108
  }
114
109
  /**
115
- * The compiled module for `explicitUrl` **only if a compile was already started**
116
- * for it — otherwise `null`, without starting one.
117
- *
118
- * This is the "join, don't initiate" accessor for consumers that have their own
119
- * working init path (`IfcLiteBridge.init()`): when a prewarm or a parallel load
120
- * has already fetched the binary, reuse it; when nothing has, do exactly what
121
- * this consumer did before rather than speculatively pulling 1.3 MB on a path
122
- * that may not need it.
123
- *
124
- * Awaits an in-flight compile rather than racing it with a second fetch — the
125
- * bytes are the same and already on the wire.
110
+ * Compile or join the engine binary. The pool's optional contract stays null on
111
+ * failure; the memo itself preserves rejection for the main loader's retry.
126
112
  */
127
- export function getStartedSharedWasmModule(explicitUrl) {
113
+ export function compileSharedWasmModule(explicitUrl) {
114
+ if (typeof WebAssembly === 'undefined')
115
+ return Promise.resolve(null);
128
116
  const url = resolveWasmUrl(explicitUrl);
129
- if (!url)
130
- return null;
131
- const cacheKey = url instanceof URL ? url.href : url;
132
- return sharedWasmModulePromises.get(cacheKey) ?? null;
117
+ return url ? optionalModule(acquireModule(url)) : Promise.resolve(null);
118
+ }
119
+ /**
120
+ * Prepare main init without starting a bundled fetch. Generated public init
121
+ * returns an already initialized engine BEFORE reading module_or_path. A cold
122
+ * loader reads this getter and starts/joins the strict memo inside its retry.
123
+ *
124
+ * Raw sibling URLs do not prove the installed npm asset location. Only join an
125
+ * existing optional memo there, then give the loader concrete options or no
126
+ * options. Promise<undefined> would bypass the loader's default URL selection.
127
+ * The second URL constructor uses a parameter so bundlers leave it untouched.
128
+ */
129
+ export async function prepareSharedWasmInit(resolvedUrl = resolveWasmUrl(), moduleUrl = import.meta.url) {
130
+ if (!resolvedUrl || typeof WebAssembly === 'undefined')
131
+ return undefined;
132
+ const cacheKey = resolvedUrl instanceof URL ? resolvedUrl.href : resolvedUrl;
133
+ const resolved = new URL(cacheKey, moduleUrl);
134
+ const unbundled = new URL('../../wasm/pkg/ifc-lite_bg.wasm', moduleUrl);
135
+ if (resolved.href === unbundled.href || !['http:', 'https:'].includes(resolved.protocol)) {
136
+ const cached = sharedWasmModulePromises.get(cacheKey);
137
+ const module = cached ? await optionalModule(cached) : null;
138
+ return module ? { module_or_path: module } : undefined;
139
+ }
140
+ return {
141
+ get module_or_path() { return acquireModule(cacheKey); },
142
+ };
133
143
  }
134
144
  /**
135
145
  * Start the shared fetch+compile BEFORE a file is opened, so the binary is
@@ -140,7 +150,7 @@ export function getStartedSharedWasmModule(explicitUrl) {
140
150
  * slow link the whole download sits in front of first geometry (measured 2.5 s
141
151
  * on a ~4 Mbit connection, for a 225 KB model).
142
152
  *
143
- * Fire-and-forget by design: a prewarm failure must never surface to the user or
153
+ * Fire-and-forget by design (the returned promise never rejects): a prewarm failure must never surface to the user or
144
154
  * poison the load path. `compileSharedWasmModule` already evicts a failed URL so
145
155
  * the real load retries, and every consumer falls back to its own `init()` when
146
156
  * no shared module is available. Callers decide *when* to call this (idle,
@@ -152,10 +162,13 @@ export function getStartedSharedWasmModule(explicitUrl) {
152
162
  * resolution, which is the intended usage.
153
163
  */
154
164
  export function prewarmSharedWasmModule(wasmUrl) {
155
- void compileSharedWasmModule(wasmUrl).catch((err) => {
165
+ // Resolves whether a module compiled (the viewer's `viewer_boot` field
166
+ // event times it, #6961); callers that only prewarm can ignore it.
167
+ return compileSharedWasmModule(wasmUrl).then((module) => module !== null, (err) => {
156
168
  // Unreachable in practice — compileSharedWasmModule swallows its own
157
169
  // failures and resolves null — but never let a prewarm reject unhandled.
158
170
  console.warn('[stream] wasm prewarm failed; load path will retry:', err);
171
+ return false;
159
172
  });
160
173
  }
161
174
  //# sourceMappingURL=wasm-shared-module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wasm-shared-module.js","sourceRoot":"","sources":["../src/wasm-shared-module.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wasm-shared-module.js","sourceRoot":"","sources":["../src/wasm-shared-module.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function acquireWasmStreamingOperation(operation: string): () => void;
2
+ //# sourceMappingURL=wasm-streaming-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasm-streaming-guard.d.ts","sourceRoot":"","sources":["../src/wasm-streaming-guard.ts"],"names":[],"mappings":"AAWA,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,IAAI,CAa3E"}