@ifc-lite/viewer 1.26.0 → 1.28.0

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 (150) hide show
  1. package/.turbo/turbo-build.log +45 -38
  2. package/CHANGELOG.md +93 -0
  3. package/dist/assets/{basketViewActivator-ZpTYWE3K.js → basketViewActivator-BNRDNuUJ.js} +9 -9
  4. package/dist/assets/{bcf-Ctcu_Sc2.js → bcf-DCwCuP7n.js} +56 -56
  5. package/dist/assets/{browser-DXS29_v9.js → browser-BIoDDfBW.js} +1 -1
  6. package/dist/assets/{cesium-BoVuJvTC.js → cesium-CzZn5yVA.js} +319 -319
  7. package/dist/assets/{decode-worker-CgM1iNSK.js → decode-worker-Cjign7Zh.js} +1 -1
  8. package/dist/assets/deflate-DNGgs8Ur.js +1 -0
  9. package/dist/assets/drawing-2d-D0dDf6Lh.js +257 -0
  10. package/dist/assets/e57-source-2wI9jkCA.js +1 -0
  11. package/dist/assets/exceljs.min-DsuzKYnj.js +29 -0
  12. package/dist/assets/{exporters-DSq76AVM.js → exporters-B9v81gi9.js} +1861 -1524
  13. package/dist/assets/geometry.worker-Bpa3115V.js +1 -0
  14. package/dist/assets/{geotiff-A5UjhI6L.js → geotiff-D-YCLS4g.js} +10 -10
  15. package/dist/assets/html2canvas.esm-Ge7aVWlp.js +5 -0
  16. package/dist/assets/{ids-DiLcGTer.js → ids-CCpq-5d3.js} +952 -945
  17. package/dist/assets/ifc-lite_bg-DbgS5EUA.wasm +0 -0
  18. package/dist/assets/{index-BAH8IJVR.js → index-Bgb3_Pu_.js} +47682 -42474
  19. package/dist/assets/index-BtbXFKsX.css +1 -0
  20. package/dist/assets/index.es-CWfqZyyr.js +6866 -0
  21. package/dist/assets/{jpeg-BzSkwo5D.js → jpeg-DGOAeUqU.js} +1 -1
  22. package/dist/assets/jspdf.es.min-XPLU2Wkq.js +19571 -0
  23. package/dist/assets/jspdf.plugin.autotable-BBLUVd7n.js +2 -0
  24. package/dist/assets/lens-C4p1kQ0p.js +1 -0
  25. package/dist/assets/{lerc-Cg2Rz-D5.js → lerc-1PMSCHwX.js} +1 -1
  26. package/dist/assets/{lzw-BBPPLW-0.js → lzw-C65U9lNM.js} +1 -1
  27. package/dist/assets/{maplibre-gl-Do6O5tDc.js → maplibre-gl-BF3Z0idw.js} +1 -1
  28. package/dist/assets/{native-bridge-CPojOeGE.js → native-bridge-XxXos6yI.js} +2 -2
  29. package/dist/assets/{packbits-yLSpjW-V.js → packbits-BdMWXC3m.js} +1 -1
  30. package/dist/assets/{pako.esm-Cram60i4.js → pako.esm-n3Pgozwg.js} +1 -1
  31. package/dist/assets/parser.worker-Ddwo3_06.js +182 -0
  32. package/dist/assets/pdf-CRwaZf3s.js +135 -0
  33. package/dist/assets/raw-CJgQdyuZ.js +1 -0
  34. package/dist/assets/{sandbox-CsRXlgCO.js → sandbox-0sDo3g3m.js} +3037 -2554
  35. package/dist/assets/server-client-cTCJ-853.js +719 -0
  36. package/dist/assets/{webimage-YafxjjGr.js → webimage-BtakWX7W.js} +1 -1
  37. package/dist/assets/xlsx-B1YOg2QB.js +142 -0
  38. package/dist/assets/{zip-BJqVbRkU.js → zip-DFgP-l20.js} +1 -1
  39. package/dist/assets/{zstd-CkSLOiuu.js → zstd-CmwsbxmM.js} +1 -1
  40. package/dist/index.html +10 -10
  41. package/package.json +27 -23
  42. package/src/components/mcp/PlaygroundChat.tsx +1 -0
  43. package/src/components/mcp/data.ts +6 -0
  44. package/src/components/mcp/playground-dispatcher.ts +280 -0
  45. package/src/components/mcp/playground-files.ts +33 -1
  46. package/src/components/mcp/types.ts +2 -1
  47. package/src/components/ui/combo-input.tsx +163 -0
  48. package/src/components/ui/tabs.tsx +1 -1
  49. package/src/components/viewer/CommandPalette.tsx +6 -1
  50. package/src/components/viewer/ComparePanel.tsx +420 -0
  51. package/src/components/viewer/HierarchyPanel.tsx +46 -7
  52. package/src/components/viewer/MainToolbar.tsx +19 -2
  53. package/src/components/viewer/PropertiesPanel.tsx +84 -8
  54. package/src/components/viewer/SearchInline.tsx +62 -2
  55. package/src/components/viewer/SearchModal.filter.builder.tsx +24 -393
  56. package/src/components/viewer/SearchModal.filter.editors.tsx +503 -0
  57. package/src/components/viewer/SearchModal.filter.tsx +64 -1
  58. package/src/components/viewer/SearchModal.tsx +19 -6
  59. package/src/components/viewer/ViewerLayout.tsx +5 -0
  60. package/src/components/viewer/Viewport.tsx +18 -0
  61. package/src/components/viewer/hierarchy/HierarchyNode.tsx +3 -3
  62. package/src/components/viewer/hierarchy/ifc-icons.ts +9 -0
  63. package/src/components/viewer/hierarchy/treeDataBuilder.ts +87 -0
  64. package/src/components/viewer/hierarchy/types.ts +1 -0
  65. package/src/components/viewer/hierarchy/useHierarchyTree.ts +6 -2
  66. package/src/components/viewer/lists/ColumnHeaderMenu.tsx +84 -0
  67. package/src/components/viewer/lists/ListBuilder.tsx +789 -280
  68. package/src/components/viewer/lists/ListGroupingBar.tsx +72 -0
  69. package/src/components/viewer/lists/ListPanel.tsx +49 -5
  70. package/src/components/viewer/lists/ListResultsTable.tsx +270 -176
  71. package/src/components/viewer/lists/list-table-utils.ts +123 -0
  72. package/src/components/viewer/properties/MaterialTotalsPanel.tsx +283 -0
  73. package/src/generated/mcp-catalog.json +4 -0
  74. package/src/hooks/federationLoadGate.test.ts +12 -2
  75. package/src/hooks/federationLoadGate.ts +9 -2
  76. package/src/hooks/ingest/federationAlign.ts +481 -0
  77. package/src/hooks/ingest/viewerModelIngest.ts +3 -212
  78. package/src/hooks/source-key.ts +35 -0
  79. package/src/hooks/useAlignmentLines3D.ts +1 -26
  80. package/src/hooks/useCompare.ts +0 -0
  81. package/src/hooks/useCompareOverlay.ts +119 -0
  82. package/src/hooks/useDrawingGeneration.ts +23 -1
  83. package/src/hooks/useGridLines3D.ts +140 -0
  84. package/src/hooks/useIfc.ts +1 -1
  85. package/src/hooks/useIfcCache.ts +32 -9
  86. package/src/hooks/useIfcFederation.ts +42 -810
  87. package/src/hooks/useIfcLoader.ts +361 -488
  88. package/src/hooks/useIfcServer.ts +3 -0
  89. package/src/hooks/useLens.ts +5 -1
  90. package/src/hooks/useSymbolicAnnotations.ts +70 -38
  91. package/src/lib/compare/buildFingerprints.ts +173 -0
  92. package/src/lib/compare/describeChange.ts +0 -0
  93. package/src/lib/compare/geometricData.test.ts +54 -0
  94. package/src/lib/compare/geometricData.ts +37 -0
  95. package/src/lib/compare/overlay.test.ts +99 -0
  96. package/src/lib/compare/overlay.ts +91 -0
  97. package/src/lib/geo/cesium-placement.ts +1 -1
  98. package/src/lib/geo/reproject.ts +4 -1
  99. package/src/lib/length-unit-scale.ts +41 -0
  100. package/src/lib/lists/adapter.ts +136 -11
  101. package/src/lib/lists/export/csv.ts +47 -0
  102. package/src/lib/lists/export/index.ts +49 -0
  103. package/src/lib/lists/export/model.ts +111 -0
  104. package/src/lib/lists/export/pdf.ts +67 -0
  105. package/src/lib/lists/export/xlsx.ts +83 -0
  106. package/src/lib/lists/index.ts +2 -0
  107. package/src/lib/llm/script-edit-ops.ts +23 -0
  108. package/src/lib/llm/stream-client.ts +8 -1
  109. package/src/lib/search/filter-evaluate.test.ts +81 -0
  110. package/src/lib/search/filter-evaluate.ts +59 -87
  111. package/src/lib/search/filter-match.ts +167 -0
  112. package/src/lib/search/filter-rules.test.ts +25 -0
  113. package/src/lib/search/filter-rules.ts +75 -2
  114. package/src/lib/search/filter-schema.ts +0 -0
  115. package/src/lib/search/result-export.ts +7 -1
  116. package/src/lib/slab-edit.test.ts +72 -0
  117. package/src/lib/slab-edit.ts +159 -19
  118. package/src/sdk/adapters/export-adapter.ts +9 -4
  119. package/src/sdk/adapters/query-adapter.ts +3 -3
  120. package/src/store/globalId.ts +15 -13
  121. package/src/store/index.ts +16 -1
  122. package/src/store/slices/cesiumSlice.ts +8 -1
  123. package/src/store/slices/compareSlice.ts +96 -0
  124. package/src/store/slices/lensSlice.ts +8 -0
  125. package/src/store/slices/listSlice.ts +6 -0
  126. package/src/store/slices/mutationSlice.ts +14 -6
  127. package/src/store/slices/searchSlice.ts +29 -3
  128. package/src/utils/acquireFileBuffer.test.ts +12 -4
  129. package/src/utils/desktopModelSnapshot.ts +2 -1
  130. package/src/utils/loadingUtils.ts +32 -0
  131. package/src/utils/nativeSpatialDataStore.ts +6 -0
  132. package/src/utils/serverDataModel.test.ts +6 -0
  133. package/src/utils/serverDataModel.ts +7 -0
  134. package/src/utils/spatialHierarchy.test.ts +53 -1
  135. package/src/utils/spatialHierarchy.ts +42 -2
  136. package/src/vite-env.d.ts +2 -0
  137. package/dist/assets/deflate-Cnx0il6E.js +0 -1
  138. package/dist/assets/drawing-2d-C71b8Ugx.js +0 -257
  139. package/dist/assets/e57-source-CQHxE8n3.js +0 -1
  140. package/dist/assets/geometry.worker-0Q9qEa6p.js +0 -1
  141. package/dist/assets/ifc-lite_bg-CEZnhM2e.wasm +0 -0
  142. package/dist/assets/index-B9Ug2EqU.css +0 -1
  143. package/dist/assets/lens-PYsLu_MA.js +0 -1
  144. package/dist/assets/parser.worker-8md211IW.js +0 -182
  145. package/dist/assets/raw-BQrAgxwT.js +0 -1
  146. package/dist/assets/server-client-Bk4c1CPO.js +0 -626
  147. package/src/hooks/ingest/resolveDataStoreOrAbort.test.ts +0 -61
  148. package/src/hooks/ingest/resolveDataStoreOrAbort.ts +0 -28
  149. package/src/hooks/ingest/watchedGeometryStream.test.ts +0 -78
  150. package/src/hooks/ingest/watchedGeometryStream.ts +0 -76
@@ -1,61 +0,0 @@
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
- import { describe, it } from 'node:test';
6
- import assert from 'node:assert';
7
-
8
- import { resolveDataStoreOrAbort } from './resolveDataStoreOrAbort.js';
9
-
10
- const isAbortError = (err: unknown): boolean =>
11
- err instanceof DOMException && err.name === 'AbortError';
12
-
13
- describe('resolveDataStoreOrAbort', () => {
14
- it('returns the parse result when not aborted', async () => {
15
- const store = { id: 'store' };
16
- const result = await resolveDataStoreOrAbort(Promise.resolve(store), { aborted: false });
17
- assert.equal(result, store);
18
- });
19
-
20
- it('throws AbortError and terminates without awaiting a blocked parse', async () => {
21
- let terminated = false;
22
- // A promise that never settles — mirrors a worker parse blocked on
23
- // waitForEntityIndex after the geometry loop was cancelled. The previous
24
- // code awaited this directly and hung forever.
25
- const neverSettles = new Promise<unknown>(() => {});
26
-
27
- await assert.rejects(
28
- resolveDataStoreOrAbort(neverSettles, {
29
- aborted: true,
30
- terminate: () => {
31
- terminated = true;
32
- },
33
- }),
34
- isAbortError,
35
- );
36
-
37
- assert.equal(terminated, true, 'the worker parser should be terminated on abort');
38
- });
39
-
40
- it('swallows the abandoned parse rejection on abort', async () => {
41
- // A parse that rejects after we bail must not surface as an unhandled
42
- // rejection (this test would fail the process if the .catch guard were
43
- // removed from resolveDataStoreOrAbort).
44
- const rejecting = Promise.reject(new Error('worker died after abort'));
45
-
46
- await assert.rejects(
47
- resolveDataStoreOrAbort(rejecting, { aborted: true }),
48
- isAbortError,
49
- );
50
-
51
- // Give the swallowed rejection a tick to settle.
52
- await new Promise((resolve) => setTimeout(resolve, 10));
53
- });
54
-
55
- it('works without a terminate callback', async () => {
56
- await assert.rejects(
57
- resolveDataStoreOrAbort(new Promise<unknown>(() => {}), { aborted: true }),
58
- isAbortError,
59
- );
60
- });
61
- });
@@ -1,28 +0,0 @@
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
- /**
6
- * Resolve a parse promise, unless the load was cancelled.
7
- *
8
- * A worker parse started with `waitForEntityIndex` blocks until the streaming
9
- * geometry pre-pass hands over the entity index. If the geometry loop is
10
- * cancelled before that handoff, the index never arrives and the parse promise
11
- * never settles — awaiting it would hang the whole ingest. On abort we instead
12
- * terminate the worker, abandon (and swallow) the parse promise, and throw an
13
- * `AbortError` so callers treat it as a clean cancellation (matching the
14
- * federated loader's `err.name === 'AbortError'` convention).
15
- */
16
- export async function resolveDataStoreOrAbort<T>(
17
- parsePromise: Promise<T>,
18
- opts: { aborted: boolean; terminate?: () => void },
19
- ): Promise<T> {
20
- if (opts.aborted) {
21
- opts.terminate?.();
22
- // Swallow the abandoned parse's eventual rejection so it doesn't surface
23
- // as an unhandled rejection after we've already bailed out.
24
- void parsePromise.catch(() => {});
25
- throw new DOMException('Model load aborted', 'AbortError');
26
- }
27
- return parsePromise;
28
- }
@@ -1,78 +0,0 @@
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
- import { describe, it } from 'node:test';
6
- import assert from 'node:assert';
7
-
8
- import { watchedGeometryStream } from './watchedGeometryStream.js';
9
-
10
- /** Build a controllable async source that records when return() is called. */
11
- function makeSource<T>(values: T[]): { source: AsyncIterable<T>; returned: () => boolean } {
12
- let didReturn = false;
13
- const source: AsyncIterable<T> = {
14
- [Symbol.asyncIterator]() {
15
- let i = 0;
16
- return {
17
- next: async () => (i < values.length
18
- ? { done: false, value: values[i++] }
19
- : { done: true, value: undefined as unknown as T }),
20
- return: async () => {
21
- didReturn = true;
22
- return { done: true, value: undefined as unknown as T };
23
- },
24
- };
25
- },
26
- };
27
- return { source, returned: () => didReturn };
28
- }
29
-
30
- const baseOpts = {
31
- fileName: 'test.ifc',
32
- fileSizeMB: 1,
33
- getBatchCount: () => 0,
34
- getLastTotalMeshes: () => 0,
35
- cleanupMs: 50,
36
- };
37
-
38
- describe('watchedGeometryStream', () => {
39
- it('re-yields every event in order then completes', async () => {
40
- const { source } = makeSource([1, 2, 3]);
41
- const seen: number[] = [];
42
- for await (const v of watchedGeometryStream(source, baseOpts)) seen.push(v);
43
- assert.deepStrictEqual(seen, [1, 2, 3]);
44
- });
45
-
46
- it('stops early when shouldAbort() turns true', async () => {
47
- const { source } = makeSource([1, 2, 3, 4]);
48
- const seen: number[] = [];
49
- let calls = 0;
50
- for await (const v of watchedGeometryStream(source, {
51
- ...baseOpts,
52
- // Abort after the second event has been consumed.
53
- shouldAbort: () => (++calls > 2),
54
- })) {
55
- seen.push(v);
56
- }
57
- assert.deepStrictEqual(seen, [1, 2]);
58
- });
59
-
60
- it('tears down the underlying iterator on normal completion', async () => {
61
- const { source, returned } = makeSource([1]);
62
- let count = 0;
63
- for await (const v of watchedGeometryStream(source, baseOpts)) count += v;
64
- assert.strictEqual(count, 1);
65
- assert.strictEqual(returned(), true);
66
- });
67
-
68
- it('tears down the underlying iterator when the consumer breaks early', async () => {
69
- const { source, returned } = makeSource([1, 2, 3]);
70
- const seen: number[] = [];
71
- for await (const v of watchedGeometryStream(source, baseOpts)) {
72
- seen.push(v);
73
- break;
74
- }
75
- assert.deepStrictEqual(seen, [1]);
76
- assert.strictEqual(returned(), true);
77
- });
78
- });
@@ -1,76 +0,0 @@
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
- import { getGeometryStreamWatchdogMs } from '@ifc-lite/geometry';
6
- import { boundedIteratorReturn } from './streamCleanup.js';
7
-
8
- export interface WatchedGeometryStreamOptions {
9
- /** File name, for the stall error message. */
10
- fileName: string;
11
- /** File size in MB, feeds the size-aware watchdog deadline. */
12
- fileSizeMB: number;
13
- /** Abort the stream cooperatively (e.g. user cancelled the load). */
14
- shouldAbort?: () => boolean;
15
- /** Current batch index — feeds the size-aware watchdog deadline. */
16
- getBatchCount: () => number;
17
- /** Meshes rendered so far, for the stall error message. */
18
- getLastTotalMeshes: () => number;
19
- /** Override the abandon-cleanup deadline (mostly for tests). */
20
- cleanupMs?: number;
21
- }
22
-
23
- /**
24
- * Drive a geometry stream under a size-aware watchdog, re-yielding every event.
25
- *
26
- * The parallel pipeline only ends once EVERY spawned geometry worker reports
27
- * `complete`; if the browser fails to instantiate a worker (the "Attempting to
28
- * create a Worker from an empty source" warning) that worker never reports
29
- * `ready`/`complete` and never fires `onerror`, so the underlying generator can
30
- * wedge forever, stranding the load on "Processing geometry (N meshes)". Racing
31
- * each `next()` against a deadline converts that silent wedge into a thrown,
32
- * recoverable error. On ANY exit — normal completion, abort, consumer `break`,
33
- * or a watchdog throw — the `finally` bounds the underlying iterator's shutdown
34
- * so cleanup (the generator's own `finally`: freeing WASM handles, tearing down
35
- * workers) runs without re-blocking on the very stall the watchdog just escaped.
36
- *
37
- * Generic over the event type so the consumer keeps full type-narrowing in its
38
- * own `switch`.
39
- */
40
- export async function* watchedGeometryStream<T>(
41
- source: AsyncIterable<T>,
42
- options: WatchedGeometryStreamOptions,
43
- ): AsyncGenerator<T> {
44
- const iterator = source[Symbol.asyncIterator]();
45
- try {
46
- while (true) {
47
- const watchdogMs = getGeometryStreamWatchdogMs({
48
- desktopStableWasm: false,
49
- batchCount: options.getBatchCount(),
50
- fileSizeMB: options.fileSizeMB,
51
- });
52
- let watchdogId: ReturnType<typeof setTimeout> | null = null;
53
- let result: IteratorResult<T>;
54
- try {
55
- result = await Promise.race([
56
- iterator.next(),
57
- new Promise<never>((_, reject) => {
58
- watchdogId = setTimeout(() => {
59
- reject(new Error(
60
- `Geometry stream stalled after ${watchdogMs}ms while loading ${options.fileName}. `
61
- + `Last rendered meshes: ${options.getLastTotalMeshes()}. A geometry worker likely failed to start.`,
62
- ));
63
- }, watchdogMs);
64
- }),
65
- ]);
66
- } finally {
67
- if (watchdogId !== null) clearTimeout(watchdogId);
68
- }
69
- if (result.done) return;
70
- if (options.shouldAbort?.()) return;
71
- yield result.value;
72
- }
73
- } finally {
74
- await boundedIteratorReturn(iterator, options.cleanupMs);
75
- }
76
- }