@ifc-lite/viewer 1.1.7 → 1.6.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 (164) hide show
  1. package/LICENSE +373 -0
  2. package/dist/apple-touch-icon.png +0 -0
  3. package/dist/assets/Arrow.dom-BjDQoB2M.js +20 -0
  4. package/dist/assets/arrow2-bb-jcVEo.js +2 -0
  5. package/dist/assets/arrow2_bg-4Y7xYo54.wasm +0 -0
  6. package/dist/assets/arrow2_bg-BlXl-cSQ.js +1 -0
  7. package/dist/assets/arrow2_bg-BoXCojjR.wasm +0 -0
  8. package/dist/assets/desktop-cache-oPzaWXYE.js +1 -0
  9. package/dist/assets/event-DIOks52T.js +1 -0
  10. package/dist/assets/ifc-cache-BAN4vcd4.js +1 -0
  11. package/dist/assets/ifc-lite_bg-C6kblxf9.wasm +0 -0
  12. package/dist/assets/index-YBtrHPu3.js +65252 -0
  13. package/dist/assets/index-v3mcCUPN.css +1 -0
  14. package/dist/assets/native-bridge-CULtTDX3.js +111 -0
  15. package/dist/assets/wasm-bridge-CjL-lSak.js +1 -0
  16. package/dist/favicon-16x16-cropped.png +0 -0
  17. package/dist/favicon-16x16.png +0 -0
  18. package/dist/favicon-192x192-cropped.png +0 -0
  19. package/dist/favicon-192x192.png +0 -0
  20. package/dist/favicon-32x32-cropped.png +0 -0
  21. package/dist/favicon-32x32.png +0 -0
  22. package/dist/favicon-48x48-cropped.png +0 -0
  23. package/dist/favicon-48x48.png +0 -0
  24. package/dist/favicon-512x512-cropped.png +0 -0
  25. package/dist/favicon-512x512.png +0 -0
  26. package/dist/favicon-64x64-cropped.png +0 -0
  27. package/dist/favicon-64x64.png +0 -0
  28. package/dist/favicon-96x96-cropped.png +0 -0
  29. package/dist/favicon-96x96.png +0 -0
  30. package/dist/favicon-square-512.png +0 -0
  31. package/dist/favicon.ico +0 -0
  32. package/dist/favicon.png +0 -0
  33. package/dist/favicon.svg +3 -0
  34. package/dist/index.html +44 -0
  35. package/dist/logo.png +0 -0
  36. package/dist/manifest.json +48 -0
  37. package/index.html +33 -2
  38. package/package.json +34 -17
  39. package/public/apple-touch-icon.png +0 -0
  40. package/public/favicon-16x16-cropped.png +0 -0
  41. package/public/favicon-16x16.png +0 -0
  42. package/public/favicon-192x192-cropped.png +0 -0
  43. package/public/favicon-192x192.png +0 -0
  44. package/public/favicon-32x32-cropped.png +0 -0
  45. package/public/favicon-32x32.png +0 -0
  46. package/public/favicon-48x48-cropped.png +0 -0
  47. package/public/favicon-48x48.png +0 -0
  48. package/public/favicon-512x512-cropped.png +0 -0
  49. package/public/favicon-512x512.png +0 -0
  50. package/public/favicon-64x64-cropped.png +0 -0
  51. package/public/favicon-64x64.png +0 -0
  52. package/public/favicon-96x96-cropped.png +0 -0
  53. package/public/favicon-96x96.png +0 -0
  54. package/public/favicon-square-512.png +0 -0
  55. package/public/favicon.ico +0 -0
  56. package/public/favicon.png +0 -0
  57. package/public/favicon.svg +3 -0
  58. package/public/logo.png +0 -0
  59. package/public/manifest.json +48 -0
  60. package/src/App.tsx +2 -0
  61. package/src/components/ui/alert.tsx +62 -0
  62. package/src/components/ui/badge.tsx +39 -0
  63. package/src/components/ui/dialog.tsx +120 -0
  64. package/src/components/ui/label.tsx +27 -0
  65. package/src/components/ui/select.tsx +151 -0
  66. package/src/components/ui/switch.tsx +30 -0
  67. package/src/components/ui/table.tsx +120 -0
  68. package/src/components/ui/tabs.tsx +1 -1
  69. package/src/components/viewer/BCFPanel.tsx +1164 -0
  70. package/src/components/viewer/BulkPropertyEditor.tsx +875 -0
  71. package/src/components/viewer/DataConnector.tsx +840 -0
  72. package/src/components/viewer/DrawingSettingsPanel.tsx +536 -0
  73. package/src/components/viewer/EntityContextMenu.tsx +45 -17
  74. package/src/components/viewer/ExportChangesButton.tsx +195 -0
  75. package/src/components/viewer/ExportDialog.tsx +402 -0
  76. package/src/components/viewer/HierarchyPanel.tsx +1132 -218
  77. package/src/components/viewer/IDSPanel.tsx +661 -0
  78. package/src/components/viewer/KeyboardShortcutsDialog.tsx +245 -39
  79. package/src/components/viewer/MainToolbar.tsx +418 -94
  80. package/src/components/viewer/PropertiesPanel.tsx +1355 -91
  81. package/src/components/viewer/PropertyEditor.tsx +611 -0
  82. package/src/components/viewer/Section2DPanel.tsx +3313 -0
  83. package/src/components/viewer/SheetSetupPanel.tsx +502 -0
  84. package/src/components/viewer/StatusBar.tsx +27 -16
  85. package/src/components/viewer/TitleBlockEditor.tsx +437 -0
  86. package/src/components/viewer/ToolOverlays.tsx +935 -127
  87. package/src/components/viewer/ViewerLayout.tsx +40 -11
  88. package/src/components/viewer/Viewport.tsx +1276 -336
  89. package/src/components/viewer/ViewportContainer.tsx +554 -18
  90. package/src/components/viewer/ViewportOverlays.tsx +24 -7
  91. package/src/hooks/useBCF.ts +504 -0
  92. package/src/hooks/useIDS.ts +1065 -0
  93. package/src/hooks/useIfc.ts +1534 -205
  94. package/src/hooks/useIfcCache.ts +279 -0
  95. package/src/hooks/useKeyboardShortcuts.ts +50 -8
  96. package/src/hooks/useModelSelection.ts +61 -0
  97. package/src/hooks/useViewerSelectors.ts +218 -0
  98. package/src/hooks/useWebGPU.ts +80 -0
  99. package/src/index.css +265 -27
  100. package/src/lib/platform.ts +23 -0
  101. package/src/services/cacheService.ts +142 -0
  102. package/src/services/desktop-cache.ts +143 -0
  103. package/src/services/fs-cache.ts +212 -0
  104. package/src/services/ifc-cache.ts +14 -6
  105. package/src/store/constants.ts +85 -0
  106. package/src/store/index.ts +214 -0
  107. package/src/store/slices/bcfSlice.ts +372 -0
  108. package/src/store/slices/cameraSlice.ts +63 -0
  109. package/src/store/slices/dataSlice.test.ts +226 -0
  110. package/src/store/slices/dataSlice.ts +112 -0
  111. package/src/store/slices/drawing2DSlice.ts +340 -0
  112. package/src/store/slices/hoverSlice.ts +40 -0
  113. package/src/store/slices/idsSlice.ts +310 -0
  114. package/src/store/slices/loadingSlice.ts +33 -0
  115. package/src/store/slices/measurementSlice.test.ts +217 -0
  116. package/src/store/slices/measurementSlice.ts +293 -0
  117. package/src/store/slices/modelSlice.test.ts +271 -0
  118. package/src/store/slices/modelSlice.ts +211 -0
  119. package/src/store/slices/mutationSlice.ts +502 -0
  120. package/src/store/slices/sectionSlice.test.ts +125 -0
  121. package/src/store/slices/sectionSlice.ts +58 -0
  122. package/src/store/slices/selectionSlice.test.ts +286 -0
  123. package/src/store/slices/selectionSlice.ts +263 -0
  124. package/src/store/slices/sheetSlice.ts +565 -0
  125. package/src/store/slices/uiSlice.ts +58 -0
  126. package/src/store/slices/visibilitySlice.test.ts +304 -0
  127. package/src/store/slices/visibilitySlice.ts +277 -0
  128. package/src/store/types.test.ts +135 -0
  129. package/src/store/types.ts +248 -0
  130. package/src/store.ts +40 -515
  131. package/src/utils/ifcConfig.ts +82 -0
  132. package/src/utils/localParsingUtils.ts +287 -0
  133. package/src/utils/serverDataModel.ts +783 -0
  134. package/src/utils/spatialHierarchy.ts +283 -0
  135. package/src/utils/viewportUtils.ts +334 -0
  136. package/src/vite-env.d.ts +23 -0
  137. package/src/webgpu-types.d.ts +128 -0
  138. package/src-tauri/Cargo.toml +29 -0
  139. package/src-tauri/build.rs +7 -0
  140. package/src-tauri/capabilities/default.json +18 -0
  141. package/src-tauri/icons/128x128.png +0 -0
  142. package/src-tauri/icons/128x128@2x.png +0 -0
  143. package/src-tauri/icons/32x32.png +0 -0
  144. package/src-tauri/icons/Square107x107Logo.png +0 -0
  145. package/src-tauri/icons/Square142x142Logo.png +0 -0
  146. package/src-tauri/icons/Square150x150Logo.png +0 -0
  147. package/src-tauri/icons/Square284x284Logo.png +0 -0
  148. package/src-tauri/icons/Square30x30Logo.png +0 -0
  149. package/src-tauri/icons/Square310x310Logo.png +0 -0
  150. package/src-tauri/icons/Square44x44Logo.png +0 -0
  151. package/src-tauri/icons/Square71x71Logo.png +0 -0
  152. package/src-tauri/icons/Square89x89Logo.png +0 -0
  153. package/src-tauri/icons/StoreLogo.png +0 -0
  154. package/src-tauri/icons/icon.icns +0 -0
  155. package/src-tauri/icons/icon.ico +0 -0
  156. package/src-tauri/icons/icon.png +0 -0
  157. package/src-tauri/src/lib.rs +21 -0
  158. package/src-tauri/src/main.rs +10 -0
  159. package/src-tauri/tauri.conf.json +39 -0
  160. package/vite.config.ts +174 -26
  161. package/public/ifc-lite_bg.wasm +0 -0
  162. package/public/web-ifc.wasm +0 -0
  163. package/src/components/Viewport.tsx +0 -723
  164. package/src/components/viewer/BoxSelectionOverlay.tsx +0 -53
@@ -6,6 +6,134 @@
6
6
  * WebGPU type definitions for TypeScript
7
7
  */
8
8
 
9
+ // Extend Navigator interface with WebGPU support
10
+ interface Navigator {
11
+ readonly gpu?: GPU;
12
+ }
13
+
14
+ // GPU interface for WebGPU API
15
+ interface GPU {
16
+ requestAdapter(options?: GPURequestAdapterOptions): Promise<GPUAdapter | null>;
17
+ getPreferredCanvasFormat(): GPUTextureFormat;
18
+ }
19
+
20
+ interface GPURequestAdapterOptions {
21
+ powerPreference?: 'low-power' | 'high-performance';
22
+ forceFallbackAdapter?: boolean;
23
+ }
24
+
25
+ interface GPUAdapter {
26
+ readonly features: GPUSupportedFeatures;
27
+ readonly limits: GPUSupportedLimits;
28
+ readonly isFallbackAdapter: boolean;
29
+ requestDevice(descriptor?: GPUDeviceDescriptor): Promise<GPUDevice>;
30
+ requestAdapterInfo(): Promise<GPUAdapterInfo>;
31
+ }
32
+
33
+ interface GPUSupportedFeatures extends ReadonlySet<string> {}
34
+
35
+ interface GPUSupportedLimits {
36
+ readonly maxTextureDimension1D: number;
37
+ readonly maxTextureDimension2D: number;
38
+ readonly maxTextureDimension3D: number;
39
+ readonly maxTextureArrayLayers: number;
40
+ readonly maxBindGroups: number;
41
+ readonly maxBindingsPerBindGroup: number;
42
+ readonly maxDynamicUniformBuffersPerPipelineLayout: number;
43
+ readonly maxDynamicStorageBuffersPerPipelineLayout: number;
44
+ readonly maxSampledTexturesPerShaderStage: number;
45
+ readonly maxSamplersPerShaderStage: number;
46
+ readonly maxStorageBuffersPerShaderStage: number;
47
+ readonly maxStorageTexturesPerShaderStage: number;
48
+ readonly maxUniformBuffersPerShaderStage: number;
49
+ readonly maxUniformBufferBindingSize: number;
50
+ readonly maxStorageBufferBindingSize: number;
51
+ readonly minUniformBufferOffsetAlignment: number;
52
+ readonly minStorageBufferOffsetAlignment: number;
53
+ readonly maxVertexBuffers: number;
54
+ readonly maxBufferSize: number;
55
+ readonly maxVertexAttributes: number;
56
+ readonly maxVertexBufferArrayStride: number;
57
+ readonly maxInterStageShaderComponents: number;
58
+ readonly maxColorAttachments: number;
59
+ readonly maxColorAttachmentBytesPerSample: number;
60
+ readonly maxComputeWorkgroupStorageSize: number;
61
+ readonly maxComputeInvocationsPerWorkgroup: number;
62
+ readonly maxComputeWorkgroupSizeX: number;
63
+ readonly maxComputeWorkgroupSizeY: number;
64
+ readonly maxComputeWorkgroupSizeZ: number;
65
+ readonly maxComputeWorkgroupsPerDimension: number;
66
+ }
67
+
68
+ interface GPUDeviceDescriptor {
69
+ requiredFeatures?: Iterable<string>;
70
+ requiredLimits?: Record<string, number>;
71
+ label?: string;
72
+ }
73
+
74
+ interface GPUDevice extends EventTarget {
75
+ readonly features: GPUSupportedFeatures;
76
+ readonly limits: GPUSupportedLimits;
77
+ readonly queue: GPUQueue;
78
+ readonly lost: Promise<GPUDeviceLostInfo>;
79
+ destroy(): void;
80
+ createBuffer(descriptor: GPUBufferDescriptor): GPUBuffer;
81
+ createTexture(descriptor: GPUTextureDescriptor): GPUTexture;
82
+ createSampler(descriptor?: GPUSamplerDescriptor): GPUSampler;
83
+ createBindGroupLayout(descriptor: GPUBindGroupLayoutDescriptor): GPUBindGroupLayout;
84
+ createPipelineLayout(descriptor: GPUPipelineLayoutDescriptor): GPUPipelineLayout;
85
+ createBindGroup(descriptor: GPUBindGroupDescriptor): GPUBindGroup;
86
+ createShaderModule(descriptor: GPUShaderModuleDescriptor): GPUShaderModule;
87
+ createComputePipeline(descriptor: GPUComputePipelineDescriptor): GPUComputePipeline;
88
+ createRenderPipeline(descriptor: GPURenderPipelineDescriptor): GPURenderPipeline;
89
+ createComputePipelineAsync(descriptor: GPUComputePipelineDescriptor): Promise<GPUComputePipeline>;
90
+ createRenderPipelineAsync(descriptor: GPURenderPipelineDescriptor): Promise<GPURenderPipeline>;
91
+ createCommandEncoder(descriptor?: GPUCommandEncoderDescriptor): GPUCommandEncoder;
92
+ createRenderBundleEncoder(descriptor: GPURenderBundleEncoderDescriptor): GPURenderBundleEncoder;
93
+ createQuerySet(descriptor: GPUQuerySetDescriptor): GPUQuerySet;
94
+ }
95
+
96
+ interface GPUAdapterInfo {
97
+ readonly vendor: string;
98
+ readonly architecture: string;
99
+ readonly device: string;
100
+ readonly description: string;
101
+ }
102
+
103
+ interface GPUDeviceLostInfo {
104
+ readonly reason: 'unknown' | 'destroyed';
105
+ readonly message: string;
106
+ }
107
+
108
+ type GPUTextureFormat = string;
109
+
110
+ // Minimal interfaces for other GPU types (as placeholders)
111
+ interface GPUQueue {}
112
+ interface GPUBuffer {}
113
+ interface GPUTexture {}
114
+ interface GPUSampler {}
115
+ interface GPUBindGroupLayout {}
116
+ interface GPUPipelineLayout {}
117
+ interface GPUBindGroup {}
118
+ interface GPUShaderModule {}
119
+ interface GPUComputePipeline {}
120
+ interface GPURenderPipeline {}
121
+ interface GPUCommandEncoder {}
122
+ interface GPURenderBundleEncoder {}
123
+ interface GPUQuerySet {}
124
+ interface GPUBufferDescriptor {}
125
+ interface GPUTextureDescriptor {}
126
+ interface GPUSamplerDescriptor {}
127
+ interface GPUBindGroupLayoutDescriptor {}
128
+ interface GPUPipelineLayoutDescriptor {}
129
+ interface GPUBindGroupDescriptor {}
130
+ interface GPUShaderModuleDescriptor {}
131
+ interface GPUComputePipelineDescriptor {}
132
+ interface GPURenderPipelineDescriptor {}
133
+ interface GPUCommandEncoderDescriptor {}
134
+ interface GPURenderBundleEncoderDescriptor {}
135
+ interface GPUQuerySetDescriptor {}
136
+
9
137
  declare const GPUBufferUsage: {
10
138
  readonly MAP_READ: number;
11
139
  readonly MAP_WRITE: number;
@@ -0,0 +1,29 @@
1
+ [package]
2
+ name = "app"
3
+ version = "0.1.0"
4
+ description = "A Tauri App"
5
+ authors = ["you"]
6
+ license = ""
7
+ repository = ""
8
+ edition = "2021"
9
+ rust-version = "1.77.2"
10
+
11
+ # Exclude from parent workspace
12
+ [workspace]
13
+
14
+ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
15
+
16
+ [lib]
17
+ name = "app_lib"
18
+ crate-type = ["staticlib", "cdylib", "rlib"]
19
+
20
+ [build-dependencies]
21
+ tauri-build = { version = "2.5.3", features = [] }
22
+
23
+ [dependencies]
24
+ serde_json = "1.0"
25
+ serde = { version = "1.0", features = ["derive"] }
26
+ log = "0.4"
27
+ tauri = { version = "2.9.5", features = [] }
28
+ tauri-plugin-log = "2"
29
+ tauri-plugin-fs = "2"
@@ -0,0 +1,7 @@
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
+ fn main() {
6
+ tauri_build::build()
7
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "../gen/schemas/desktop-schema.json",
3
+ "identifier": "default",
4
+ "description": "enables the default permissions",
5
+ "windows": [
6
+ "main"
7
+ ],
8
+ "permissions": [
9
+ "core:default",
10
+ "fs:allow-read-file",
11
+ "fs:allow-write-file",
12
+ "fs:allow-read-dir",
13
+ "fs:allow-create",
14
+ "fs:allow-exists",
15
+ "fs:allow-remove",
16
+ "fs:scope-appdata"
17
+ ]
18
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,21 @@
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
+ #[cfg_attr(mobile, tauri::mobile_entry_point)]
6
+ pub fn run() {
7
+ tauri::Builder::default()
8
+ .plugin(tauri_plugin_fs::init())
9
+ .setup(|app| {
10
+ if cfg!(debug_assertions) {
11
+ app.handle().plugin(
12
+ tauri_plugin_log::Builder::default()
13
+ .level(log::LevelFilter::Info)
14
+ .build(),
15
+ )?;
16
+ }
17
+ Ok(())
18
+ })
19
+ .run(tauri::generate_context!())
20
+ .expect("error while running tauri application");
21
+ }
@@ -0,0 +1,10 @@
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
+ // Prevents additional console window on Windows in release, DO NOT REMOVE!!
6
+ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
7
+
8
+ fn main() {
9
+ app_lib::run();
10
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "$schema": "../../../node_modules/@tauri-apps/cli/config.schema.json",
3
+ "productName": "IFC-Lite",
4
+ "version": "0.1.0",
5
+ "identifier": "com.tauri.dev",
6
+ "build": {
7
+ "frontendDist": "../dist",
8
+ "devUrl": "http://127.0.0.1:3000",
9
+ "beforeDevCommand": "pnpm dev",
10
+ "beforeBuildCommand": "pnpm build"
11
+ },
12
+ "app": {
13
+ "windows": [
14
+ {
15
+ "title": "IFC-Lite Viewer",
16
+ "width": 1400,
17
+ "height": 900,
18
+ "resizable": true,
19
+ "fullscreen": false,
20
+ "minWidth": 800,
21
+ "minHeight": 600
22
+ }
23
+ ],
24
+ "security": {
25
+ "csp": null
26
+ }
27
+ },
28
+ "bundle": {
29
+ "active": true,
30
+ "targets": "all",
31
+ "icon": [
32
+ "icons/32x32.png",
33
+ "icons/128x128.png",
34
+ "icons/128x128@2x.png",
35
+ "icons/icon.icns",
36
+ "icons/icon.ico"
37
+ ]
38
+ }
39
+ }
package/vite.config.ts CHANGED
@@ -1,9 +1,173 @@
1
1
  import { defineConfig } from 'vite';
2
2
  import react from '@vitejs/plugin-react';
3
+ import wasm from 'vite-plugin-wasm';
4
+ import topLevelAwait from 'vite-plugin-top-level-await';
3
5
  import path from 'path';
6
+ import fs from 'fs';
7
+
8
+ // --- Build-time changelog parser ---
9
+
10
+ interface ReleaseHighlight {
11
+ type: 'feature' | 'fix' | 'perf';
12
+ text: string;
13
+ }
14
+
15
+ interface Release {
16
+ version: string;
17
+ highlights: ReleaseHighlight[];
18
+ }
19
+
20
+ const SKIP_BOLD_LOWER = new Set([
21
+ 'bug fixes', 'new features', 'performance improvements', 'technical details',
22
+ 'renderer fixes', 'parser fixes', 'viewer integration', 'fixes', 'features',
23
+ 'breaking', 'minor changes', 'patch changes', 'dependencies',
24
+ ]);
25
+
26
+ function isInternalName(text: string): boolean {
27
+ // Skip PascalCase single-word class names like "PolygonalFaceSetProcessor"
28
+ return /^[A-Z][a-zA-Z]+$/.test(text) && !text.includes(' ');
29
+ }
30
+
31
+ function categorizeHighlight(text: string): 'feature' | 'fix' | 'perf' {
32
+ const lower = text.toLowerCase();
33
+ if (lower.startsWith('fixed ') || lower.startsWith('fix ')) return 'fix';
34
+ if (
35
+ lower.includes('performance') || lower.includes('optimiz') ||
36
+ lower.includes('zero-copy') || lower.includes('faster') ||
37
+ lower.includes('batch siz')
38
+ ) return 'perf';
39
+ return 'feature';
40
+ }
41
+
42
+ function extractBulletDescription(line: string): string | null {
43
+ let text = line.replace(/^-\s+/, '');
44
+
45
+ // Pattern: "HASH: ### Header" -> skip inline section headers
46
+ if (/^[a-f0-9]{7,}:\s*###/.test(text)) return null;
47
+
48
+ // Pattern: "HASH: feat/fix/perf: DESCRIPTION"
49
+ const hashPrefixed = text.match(/^[a-f0-9]{7,}:\s*(?:feat|fix|perf|refactor|chore):\s*(.+)$/i);
50
+ if (hashPrefixed) return hashPrefixed[1].trim();
51
+
52
+ // Pattern: "HASH: DESCRIPTION" (without conventional commit prefix)
53
+ const hashOnly = text.match(/^[a-f0-9]{7,}:\s*(.+)$/);
54
+ if (hashOnly) return hashOnly[1].trim();
55
+
56
+ // Pattern: "[#PR](url) [`hash`](url) Thanks @user! - DESCRIPTION"
57
+ const prPattern = text.match(/Thanks\s+\[@[^\]]+\]\([^)]+\)!\s*-\s*(.+)$/);
58
+ if (prPattern) return prPattern[1].trim();
59
+
60
+ return null;
61
+ }
62
+
63
+ function compareSemver(a: string, b: string): number {
64
+ const pa = a.split('.').map(Number);
65
+ const pb = b.split('.').map(Number);
66
+ for (let i = 0; i < 3; i++) {
67
+ if (pa[i] !== pb[i]) return pa[i] - pb[i];
68
+ }
69
+ return 0;
70
+ }
71
+
72
+ function parseChangelogs(): Release[] {
73
+ const packagesDir = path.resolve(__dirname, '../../packages');
74
+ let dirs: string[];
75
+ try {
76
+ dirs = fs.readdirSync(packagesDir);
77
+ } catch {
78
+ return [];
79
+ }
80
+
81
+ const versionMap = new Map<string, Map<string, ReleaseHighlight>>();
82
+ const seenVersionsPerFile = new Map<string, Set<string>>();
83
+
84
+ for (const dir of dirs) {
85
+ const changelogPath = path.join(packagesDir, dir, 'CHANGELOG.md');
86
+ if (!fs.existsSync(changelogPath)) continue;
87
+
88
+ const content = fs.readFileSync(changelogPath, 'utf-8');
89
+ const fileKey = dir;
90
+ seenVersionsPerFile.set(fileKey, new Set());
91
+
92
+ // Split into version blocks
93
+ const versionBlocks = content.split(/^## /m).slice(1);
94
+
95
+ for (const block of versionBlocks) {
96
+ const versionMatch = block.match(/^(\d+\.\d+\.\d+)/);
97
+ if (!versionMatch) continue;
98
+ const version = versionMatch[1];
99
+
100
+ // Skip duplicate version sections within same file
101
+ if (seenVersionsPerFile.get(fileKey)!.has(version)) continue;
102
+ seenVersionsPerFile.get(fileKey)!.add(version);
103
+
104
+ if (!versionMap.has(version)) {
105
+ versionMap.set(version, new Map());
106
+ }
107
+ const highlights = versionMap.get(version)!;
108
+
109
+ const lines = block.split('\n');
110
+
111
+ // 1) Extract top-level bullet descriptions (lines starting with "- " at root indent)
112
+ for (const line of lines) {
113
+ if (!line.startsWith('- ')) continue;
114
+ if (line.startsWith('- Updated dependencies')) continue;
115
+
116
+ const desc = extractBulletDescription(line);
117
+ if (desc && desc.length >= 10) {
118
+ const key = desc.toLowerCase().substring(0, 60);
119
+ if (!highlights.has(key)) {
120
+ highlights.set(key, { type: categorizeHighlight(desc), text: desc });
121
+ }
122
+ }
123
+ }
124
+
125
+ // 2) Extract bold items as highlights (nested feature names)
126
+ const boldRegex = /\*\*([^*]+)\*\*/g;
127
+ let match;
128
+ while ((match = boldRegex.exec(block)) !== null) {
129
+ let text = match[1].trim();
130
+ if (text.endsWith(':')) text = text.slice(0, -1);
131
+ if (text.includes('@ifc-lite/')) continue;
132
+ if (SKIP_BOLD_LOWER.has(text.toLowerCase())) continue;
133
+ if (text.length < 10) continue;
134
+ if (isInternalName(text)) continue;
135
+
136
+ const key = text.toLowerCase().substring(0, 60);
137
+ if (!highlights.has(key)) {
138
+ highlights.set(key, { type: categorizeHighlight(text), text });
139
+ }
140
+ }
141
+ }
142
+ }
143
+
144
+ const MAX_HIGHLIGHTS_PER_VERSION = 12;
145
+
146
+ return Array.from(versionMap.entries())
147
+ .sort((a, b) => compareSemver(b[0], a[0]))
148
+ .map(([version, highlights]) => ({
149
+ version,
150
+ highlights: Array.from(highlights.values()).slice(0, MAX_HIGHLIGHTS_PER_VERSION),
151
+ }))
152
+ .filter((r) => r.highlights.length > 0);
153
+ }
154
+
155
+ // Read version from root package.json
156
+ const rootPkg = JSON.parse(
157
+ fs.readFileSync(path.resolve(__dirname, '../../package.json'), 'utf-8')
158
+ );
4
159
 
5
160
  export default defineConfig({
6
- plugins: [react()],
161
+ plugins: [
162
+ react(),
163
+ wasm(),
164
+ topLevelAwait(),
165
+ ],
166
+ define: {
167
+ __APP_VERSION__: JSON.stringify(rootPkg.version),
168
+ __BUILD_DATE__: JSON.stringify(new Date().toISOString()),
169
+ __RELEASE_HISTORY__: JSON.stringify(parseChangelogs()),
170
+ },
7
171
  resolve: {
8
172
  alias: {
9
173
  '@': path.resolve(__dirname, './src'),
@@ -11,49 +175,33 @@ export default defineConfig({
11
175
  '@ifc-lite/geometry': path.resolve(__dirname, '../../packages/geometry/src'),
12
176
  '@ifc-lite/renderer': path.resolve(__dirname, '../../packages/renderer/src'),
13
177
  '@ifc-lite/query': path.resolve(__dirname, '../../packages/query/src'),
178
+ '@ifc-lite/server-client': path.resolve(__dirname, '../../packages/server-client/src'),
14
179
  '@ifc-lite/spatial': path.resolve(__dirname, '../../packages/spatial/src'),
15
180
  '@ifc-lite/data': path.resolve(__dirname, '../../packages/data/src'),
16
181
  '@ifc-lite/export': path.resolve(__dirname, '../../packages/export/src'),
17
182
  '@ifc-lite/cache': path.resolve(__dirname, '../../packages/cache/src'),
183
+ '@ifc-lite/ifcx': path.resolve(__dirname, '../../packages/ifcx/src'),
18
184
  '@ifc-lite/wasm': path.resolve(__dirname, '../../packages/wasm/pkg/ifc-lite.js'),
19
185
  },
20
186
  },
21
187
  server: {
22
188
  port: 3000,
23
- open: true,
24
- hmr: {
25
- overlay: true,
189
+ headers: {
190
+ 'Cross-Origin-Opener-Policy': 'same-origin',
191
+ 'Cross-Origin-Embedder-Policy': 'require-corp',
26
192
  },
27
- watch: {
28
- usePolling: false,
29
- ignored: ['**/node_modules/**', '**/dist/**', '**/target/**', '**/pkg/**'],
193
+ fs: {
194
+ allow: ['../..'],
30
195
  },
31
196
  },
32
197
  build: {
33
198
  target: 'esnext',
34
199
  },
35
200
  optimizeDeps: {
36
- exclude: ['@duckdb/duckdb-wasm'], // Optional dependency, exclude from pre-bundling
201
+ exclude: ['@duckdb/duckdb-wasm', '@ifc-lite/wasm', 'parquet-wasm'],
37
202
  },
38
- assetsInclude: ['**/*.wasm'],
39
203
  worker: {
40
204
  format: 'es',
41
- plugins: () => [
42
- react(),
43
- // Resolve aliases in worker context
44
- {
45
- name: 'worker-alias-resolver',
46
- resolveId(id) {
47
- if (id.startsWith('@ifc-lite/')) {
48
- const packageName = id.split('/')[1];
49
- // WASM package doesn't have src folder - use pkg
50
- if (packageName === 'wasm') {
51
- return path.resolve(__dirname, `../../packages/wasm/pkg/ifc-lite.js`);
52
- }
53
- return path.resolve(__dirname, `../../packages/${packageName}/src`);
54
- }
55
- },
56
- },
57
- ],
205
+ plugins: () => [wasm(), topLevelAwait()],
58
206
  },
59
207
  });
Binary file
Binary file