@ifc-lite/viewer 1.17.3 → 1.17.6

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 (530) hide show
  1. package/.turbo/turbo-build.log +39 -30
  2. package/.turbo/turbo-typecheck.log +1 -1
  3. package/CHANGELOG.md +132 -0
  4. package/DESKTOP_CONTRACT_VERSION +1 -0
  5. package/dist/assets/arrow-CZ5kQ26f.js +20 -0
  6. package/dist/assets/basketViewActivator-86rgogji.js +1 -0
  7. package/dist/assets/{bcf-D5-QWGO9.js → bcf-DOG9_WPX.js} +1 -1
  8. package/dist/assets/{browser-CKs-FY1P.js → browser-C5TFR7sH.js} +1 -1
  9. package/dist/assets/cesium-ADbP7waU.css +1 -0
  10. package/dist/assets/cesium-DUOzBlqv.js +17817 -0
  11. package/dist/assets/drawing-2d-DoxKMqbO.js +257 -0
  12. package/dist/assets/{exporters-C_6J153K.js → exporters-CcPS9MK5.js} +2898 -2380
  13. package/dist/assets/geometry.worker-BFUYA08u.js +1 -0
  14. package/dist/assets/ids-DQ5jY0E8.js +1 -0
  15. package/dist/assets/ifc-lite_bg-BINvzoCP.wasm +0 -0
  16. package/dist/assets/{index-jhBr1wbn.js → index-Bfms9I4A.js} +41036 -34613
  17. package/dist/assets/index-_bfZsDCC.css +1 -0
  18. package/dist/assets/{maplibre-gl-BpvwNKKy.js → maplibre-gl-CGLcoNXc.js} +1 -1
  19. package/dist/assets/native-bridge-DUyLCMZS.js +429 -0
  20. package/dist/assets/{sandbox-B79eavQ3.js → sandbox-C8575tul.js} +4342 -4324
  21. package/dist/assets/{server-client-D3bUPJJc.js → server-client-BuZK7OST.js} +4 -4
  22. package/dist/assets/tauri-core-stub-D8Fa-u43.js +1 -0
  23. package/dist/assets/tauri-dialog-stub-r7Wksg7o.js +1 -0
  24. package/dist/assets/tauri-fs-stub-BdeRC7aK.js +1 -0
  25. package/dist/assets/wasm-bridge-JsqEGDV8.js +1 -0
  26. package/dist/assets/{zip-B-jFFAGa.js → zip-DBEtpeu6.js} +3 -3
  27. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_0.json +1 -0
  28. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_1.json +1 -0
  29. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_10.json +1 -0
  30. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_11.json +1 -0
  31. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_12.json +1 -0
  32. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_13.json +1 -0
  33. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_14.json +1 -0
  34. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_15.json +1 -0
  35. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_16.json +1 -0
  36. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_17.json +1 -0
  37. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_18.json +1 -0
  38. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_19.json +1 -0
  39. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_2.json +1 -0
  40. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_20.json +1 -0
  41. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_21.json +1 -0
  42. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_22.json +1 -0
  43. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_23.json +1 -0
  44. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_24.json +1 -0
  45. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_25.json +1 -0
  46. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_26.json +1 -0
  47. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_27.json +1 -0
  48. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_3.json +1 -0
  49. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_4.json +1 -0
  50. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_5.json +1 -0
  51. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_6.json +1 -0
  52. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_7.json +1 -0
  53. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_8.json +1 -0
  54. package/dist/cesium/Assets/IAU2006_XYS/IAU2006_XYS_9.json +1 -0
  55. package/dist/cesium/Assets/Images/bing_maps_credit.png +0 -0
  56. package/dist/cesium/Assets/Images/cesium_credit.png +0 -0
  57. package/dist/cesium/Assets/Images/google_earth_credit.png +0 -0
  58. package/dist/cesium/Assets/Images/ion-credit.png +0 -0
  59. package/dist/cesium/Assets/Textures/LensFlare/DirtMask.jpg +0 -0
  60. package/dist/cesium/Assets/Textures/LensFlare/StarBurst.jpg +0 -0
  61. package/dist/cesium/Assets/Textures/NaturalEarthII/0/0/0.jpg +0 -0
  62. package/dist/cesium/Assets/Textures/NaturalEarthII/0/1/0.jpg +0 -0
  63. package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/0.jpg +0 -0
  64. package/dist/cesium/Assets/Textures/NaturalEarthII/1/0/1.jpg +0 -0
  65. package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/0.jpg +0 -0
  66. package/dist/cesium/Assets/Textures/NaturalEarthII/1/1/1.jpg +0 -0
  67. package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/0.jpg +0 -0
  68. package/dist/cesium/Assets/Textures/NaturalEarthII/1/2/1.jpg +0 -0
  69. package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/0.jpg +0 -0
  70. package/dist/cesium/Assets/Textures/NaturalEarthII/1/3/1.jpg +0 -0
  71. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/0.jpg +0 -0
  72. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/1.jpg +0 -0
  73. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/2.jpg +0 -0
  74. package/dist/cesium/Assets/Textures/NaturalEarthII/2/0/3.jpg +0 -0
  75. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/0.jpg +0 -0
  76. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/1.jpg +0 -0
  77. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/2.jpg +0 -0
  78. package/dist/cesium/Assets/Textures/NaturalEarthII/2/1/3.jpg +0 -0
  79. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/0.jpg +0 -0
  80. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/1.jpg +0 -0
  81. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/2.jpg +0 -0
  82. package/dist/cesium/Assets/Textures/NaturalEarthII/2/2/3.jpg +0 -0
  83. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/0.jpg +0 -0
  84. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/1.jpg +0 -0
  85. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/2.jpg +0 -0
  86. package/dist/cesium/Assets/Textures/NaturalEarthII/2/3/3.jpg +0 -0
  87. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/0.jpg +0 -0
  88. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/1.jpg +0 -0
  89. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/2.jpg +0 -0
  90. package/dist/cesium/Assets/Textures/NaturalEarthII/2/4/3.jpg +0 -0
  91. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/0.jpg +0 -0
  92. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/1.jpg +0 -0
  93. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/2.jpg +0 -0
  94. package/dist/cesium/Assets/Textures/NaturalEarthII/2/5/3.jpg +0 -0
  95. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/0.jpg +0 -0
  96. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/1.jpg +0 -0
  97. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/2.jpg +0 -0
  98. package/dist/cesium/Assets/Textures/NaturalEarthII/2/6/3.jpg +0 -0
  99. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/0.jpg +0 -0
  100. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/1.jpg +0 -0
  101. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/2.jpg +0 -0
  102. package/dist/cesium/Assets/Textures/NaturalEarthII/2/7/3.jpg +0 -0
  103. package/dist/cesium/Assets/Textures/NaturalEarthII/tilemapresource.xml +14 -0
  104. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mx.jpg +0 -0
  105. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_my.jpg +0 -0
  106. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_mz.jpg +0 -0
  107. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_px.jpg +0 -0
  108. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_py.jpg +0 -0
  109. package/dist/cesium/Assets/Textures/SkyBox/tycho2t3_80_pz.jpg +0 -0
  110. package/dist/cesium/Assets/Textures/maki/airfield.png +0 -0
  111. package/dist/cesium/Assets/Textures/maki/airport.png +0 -0
  112. package/dist/cesium/Assets/Textures/maki/alcohol-shop.png +0 -0
  113. package/dist/cesium/Assets/Textures/maki/america-football.png +0 -0
  114. package/dist/cesium/Assets/Textures/maki/art-gallery.png +0 -0
  115. package/dist/cesium/Assets/Textures/maki/bakery.png +0 -0
  116. package/dist/cesium/Assets/Textures/maki/bank.png +0 -0
  117. package/dist/cesium/Assets/Textures/maki/bar.png +0 -0
  118. package/dist/cesium/Assets/Textures/maki/baseball.png +0 -0
  119. package/dist/cesium/Assets/Textures/maki/basketball.png +0 -0
  120. package/dist/cesium/Assets/Textures/maki/beer.png +0 -0
  121. package/dist/cesium/Assets/Textures/maki/bicycle.png +0 -0
  122. package/dist/cesium/Assets/Textures/maki/building.png +0 -0
  123. package/dist/cesium/Assets/Textures/maki/bus.png +0 -0
  124. package/dist/cesium/Assets/Textures/maki/cafe.png +0 -0
  125. package/dist/cesium/Assets/Textures/maki/camera.png +0 -0
  126. package/dist/cesium/Assets/Textures/maki/campsite.png +0 -0
  127. package/dist/cesium/Assets/Textures/maki/car.png +0 -0
  128. package/dist/cesium/Assets/Textures/maki/cemetery.png +0 -0
  129. package/dist/cesium/Assets/Textures/maki/cesium.png +0 -0
  130. package/dist/cesium/Assets/Textures/maki/chemist.png +0 -0
  131. package/dist/cesium/Assets/Textures/maki/cinema.png +0 -0
  132. package/dist/cesium/Assets/Textures/maki/circle-stroked.png +0 -0
  133. package/dist/cesium/Assets/Textures/maki/circle.png +0 -0
  134. package/dist/cesium/Assets/Textures/maki/city.png +0 -0
  135. package/dist/cesium/Assets/Textures/maki/clothing-store.png +0 -0
  136. package/dist/cesium/Assets/Textures/maki/college.png +0 -0
  137. package/dist/cesium/Assets/Textures/maki/commercial.png +0 -0
  138. package/dist/cesium/Assets/Textures/maki/cricket.png +0 -0
  139. package/dist/cesium/Assets/Textures/maki/cross.png +0 -0
  140. package/dist/cesium/Assets/Textures/maki/dam.png +0 -0
  141. package/dist/cesium/Assets/Textures/maki/danger.png +0 -0
  142. package/dist/cesium/Assets/Textures/maki/disability.png +0 -0
  143. package/dist/cesium/Assets/Textures/maki/dog-park.png +0 -0
  144. package/dist/cesium/Assets/Textures/maki/embassy.png +0 -0
  145. package/dist/cesium/Assets/Textures/maki/emergency-telephone.png +0 -0
  146. package/dist/cesium/Assets/Textures/maki/entrance.png +0 -0
  147. package/dist/cesium/Assets/Textures/maki/farm.png +0 -0
  148. package/dist/cesium/Assets/Textures/maki/fast-food.png +0 -0
  149. package/dist/cesium/Assets/Textures/maki/ferry.png +0 -0
  150. package/dist/cesium/Assets/Textures/maki/fire-station.png +0 -0
  151. package/dist/cesium/Assets/Textures/maki/fuel.png +0 -0
  152. package/dist/cesium/Assets/Textures/maki/garden.png +0 -0
  153. package/dist/cesium/Assets/Textures/maki/gift.png +0 -0
  154. package/dist/cesium/Assets/Textures/maki/golf.png +0 -0
  155. package/dist/cesium/Assets/Textures/maki/grocery.png +0 -0
  156. package/dist/cesium/Assets/Textures/maki/hairdresser.png +0 -0
  157. package/dist/cesium/Assets/Textures/maki/harbor.png +0 -0
  158. package/dist/cesium/Assets/Textures/maki/heart.png +0 -0
  159. package/dist/cesium/Assets/Textures/maki/heliport.png +0 -0
  160. package/dist/cesium/Assets/Textures/maki/hospital.png +0 -0
  161. package/dist/cesium/Assets/Textures/maki/ice-cream.png +0 -0
  162. package/dist/cesium/Assets/Textures/maki/industrial.png +0 -0
  163. package/dist/cesium/Assets/Textures/maki/land-use.png +0 -0
  164. package/dist/cesium/Assets/Textures/maki/laundry.png +0 -0
  165. package/dist/cesium/Assets/Textures/maki/library.png +0 -0
  166. package/dist/cesium/Assets/Textures/maki/lighthouse.png +0 -0
  167. package/dist/cesium/Assets/Textures/maki/lodging.png +0 -0
  168. package/dist/cesium/Assets/Textures/maki/logging.png +0 -0
  169. package/dist/cesium/Assets/Textures/maki/london-underground.png +0 -0
  170. package/dist/cesium/Assets/Textures/maki/marker-stroked.png +0 -0
  171. package/dist/cesium/Assets/Textures/maki/marker.png +0 -0
  172. package/dist/cesium/Assets/Textures/maki/minefield.png +0 -0
  173. package/dist/cesium/Assets/Textures/maki/mobilephone.png +0 -0
  174. package/dist/cesium/Assets/Textures/maki/monument.png +0 -0
  175. package/dist/cesium/Assets/Textures/maki/museum.png +0 -0
  176. package/dist/cesium/Assets/Textures/maki/music.png +0 -0
  177. package/dist/cesium/Assets/Textures/maki/oil-well.png +0 -0
  178. package/dist/cesium/Assets/Textures/maki/park.png +0 -0
  179. package/dist/cesium/Assets/Textures/maki/park2.png +0 -0
  180. package/dist/cesium/Assets/Textures/maki/parking-garage.png +0 -0
  181. package/dist/cesium/Assets/Textures/maki/parking.png +0 -0
  182. package/dist/cesium/Assets/Textures/maki/pharmacy.png +0 -0
  183. package/dist/cesium/Assets/Textures/maki/pitch.png +0 -0
  184. package/dist/cesium/Assets/Textures/maki/place-of-worship.png +0 -0
  185. package/dist/cesium/Assets/Textures/maki/playground.png +0 -0
  186. package/dist/cesium/Assets/Textures/maki/police.png +0 -0
  187. package/dist/cesium/Assets/Textures/maki/polling-place.png +0 -0
  188. package/dist/cesium/Assets/Textures/maki/post.png +0 -0
  189. package/dist/cesium/Assets/Textures/maki/prison.png +0 -0
  190. package/dist/cesium/Assets/Textures/maki/rail-above.png +0 -0
  191. package/dist/cesium/Assets/Textures/maki/rail-light.png +0 -0
  192. package/dist/cesium/Assets/Textures/maki/rail-metro.png +0 -0
  193. package/dist/cesium/Assets/Textures/maki/rail-underground.png +0 -0
  194. package/dist/cesium/Assets/Textures/maki/rail.png +0 -0
  195. package/dist/cesium/Assets/Textures/maki/religious-christian.png +0 -0
  196. package/dist/cesium/Assets/Textures/maki/religious-jewish.png +0 -0
  197. package/dist/cesium/Assets/Textures/maki/religious-muslim.png +0 -0
  198. package/dist/cesium/Assets/Textures/maki/restaurant.png +0 -0
  199. package/dist/cesium/Assets/Textures/maki/roadblock.png +0 -0
  200. package/dist/cesium/Assets/Textures/maki/rocket.png +0 -0
  201. package/dist/cesium/Assets/Textures/maki/school.png +0 -0
  202. package/dist/cesium/Assets/Textures/maki/scooter.png +0 -0
  203. package/dist/cesium/Assets/Textures/maki/shop.png +0 -0
  204. package/dist/cesium/Assets/Textures/maki/skiing.png +0 -0
  205. package/dist/cesium/Assets/Textures/maki/slaughterhouse.png +0 -0
  206. package/dist/cesium/Assets/Textures/maki/soccer.png +0 -0
  207. package/dist/cesium/Assets/Textures/maki/square-stroked.png +0 -0
  208. package/dist/cesium/Assets/Textures/maki/square.png +0 -0
  209. package/dist/cesium/Assets/Textures/maki/star-stroked.png +0 -0
  210. package/dist/cesium/Assets/Textures/maki/star.png +0 -0
  211. package/dist/cesium/Assets/Textures/maki/suitcase.png +0 -0
  212. package/dist/cesium/Assets/Textures/maki/swimming.png +0 -0
  213. package/dist/cesium/Assets/Textures/maki/telephone.png +0 -0
  214. package/dist/cesium/Assets/Textures/maki/tennis.png +0 -0
  215. package/dist/cesium/Assets/Textures/maki/theatre.png +0 -0
  216. package/dist/cesium/Assets/Textures/maki/toilets.png +0 -0
  217. package/dist/cesium/Assets/Textures/maki/town-hall.png +0 -0
  218. package/dist/cesium/Assets/Textures/maki/town.png +0 -0
  219. package/dist/cesium/Assets/Textures/maki/triangle-stroked.png +0 -0
  220. package/dist/cesium/Assets/Textures/maki/triangle.png +0 -0
  221. package/dist/cesium/Assets/Textures/maki/village.png +0 -0
  222. package/dist/cesium/Assets/Textures/maki/warehouse.png +0 -0
  223. package/dist/cesium/Assets/Textures/maki/waste-basket.png +0 -0
  224. package/dist/cesium/Assets/Textures/maki/water.png +0 -0
  225. package/dist/cesium/Assets/Textures/maki/wetland.png +0 -0
  226. package/dist/cesium/Assets/Textures/maki/zoo.png +0 -0
  227. package/dist/cesium/Assets/Textures/moonSmall.jpg +0 -0
  228. package/dist/cesium/Assets/Textures/pin.svg +1 -0
  229. package/dist/cesium/Assets/Textures/waterNormals.jpg +0 -0
  230. package/dist/cesium/Assets/Textures/waterNormalsSmall.jpg +0 -0
  231. package/dist/cesium/Assets/approximateTerrainHeights.json +1 -0
  232. package/dist/cesium/ThirdParty/Workers/package.json +1 -0
  233. package/dist/cesium/ThirdParty/Workers/zip-web-worker.js +1 -0
  234. package/dist/cesium/ThirdParty/basis_transcoder.wasm +0 -0
  235. package/dist/cesium/ThirdParty/draco_decoder.wasm +0 -0
  236. package/dist/cesium/ThirdParty/google-earth-dbroot-parser.js +1 -0
  237. package/dist/cesium/ThirdParty/wasm_splats_bg.wasm +0 -0
  238. package/dist/cesium/ThirdParty/zip-module.wasm +0 -0
  239. package/dist/cesium/Widgets/Animation/Animation.css +127 -0
  240. package/dist/cesium/Widgets/Animation/lighter.css +70 -0
  241. package/dist/cesium/Widgets/BaseLayerPicker/BaseLayerPicker.css +108 -0
  242. package/dist/cesium/Widgets/BaseLayerPicker/lighter.css +22 -0
  243. package/dist/cesium/Widgets/Cesium3DTilesInspector/Cesium3DTilesInspector.css +102 -0
  244. package/dist/cesium/Widgets/CesiumInspector/CesiumInspector.css +113 -0
  245. package/dist/cesium/Widgets/CesiumWidget/CesiumWidget.css +119 -0
  246. package/dist/cesium/Widgets/CesiumWidget/lighter.css +14 -0
  247. package/dist/cesium/Widgets/FullscreenButton/FullscreenButton.css +8 -0
  248. package/dist/cesium/Widgets/Geocoder/Geocoder.css +70 -0
  249. package/dist/cesium/Widgets/Geocoder/lighter.css +17 -0
  250. package/dist/cesium/Widgets/I3SBuildingSceneLayerExplorer/I3SBuildingSceneLayerExplorer.css +27 -0
  251. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldHillshade.png +0 -0
  252. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldImagery.png +0 -0
  253. package/dist/cesium/Widgets/Images/ImageryProviders/ArcGisMapServiceWorldOcean.png +0 -0
  254. package/dist/cesium/Widgets/Images/ImageryProviders/azureAerial.png +0 -0
  255. package/dist/cesium/Widgets/Images/ImageryProviders/azureRoads.png +0 -0
  256. package/dist/cesium/Widgets/Images/ImageryProviders/bingAerial.png +0 -0
  257. package/dist/cesium/Widgets/Images/ImageryProviders/bingAerialLabels.png +0 -0
  258. package/dist/cesium/Widgets/Images/ImageryProviders/bingRoads.png +0 -0
  259. package/dist/cesium/Widgets/Images/ImageryProviders/blueMarble.png +0 -0
  260. package/dist/cesium/Widgets/Images/ImageryProviders/earthAtNight.png +0 -0
  261. package/dist/cesium/Widgets/Images/ImageryProviders/googleContour.png +0 -0
  262. package/dist/cesium/Widgets/Images/ImageryProviders/googleRoadmap.png +0 -0
  263. package/dist/cesium/Widgets/Images/ImageryProviders/googleSatellite.png +0 -0
  264. package/dist/cesium/Widgets/Images/ImageryProviders/googleSatelliteLabels.png +0 -0
  265. package/dist/cesium/Widgets/Images/ImageryProviders/mapQuestOpenStreetMap.png +0 -0
  266. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxSatellite.png +0 -0
  267. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxStreets.png +0 -0
  268. package/dist/cesium/Widgets/Images/ImageryProviders/mapboxTerrain.png +0 -0
  269. package/dist/cesium/Widgets/Images/ImageryProviders/naturalEarthII.png +0 -0
  270. package/dist/cesium/Widgets/Images/ImageryProviders/openStreetMap.png +0 -0
  271. package/dist/cesium/Widgets/Images/ImageryProviders/sentinel-2.png +0 -0
  272. package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmooth.png +0 -0
  273. package/dist/cesium/Widgets/Images/ImageryProviders/stadiaAlidadeSmoothDark.png +0 -0
  274. package/dist/cesium/Widgets/Images/ImageryProviders/stamenToner.png +0 -0
  275. package/dist/cesium/Widgets/Images/ImageryProviders/stamenWatercolor.png +0 -0
  276. package/dist/cesium/Widgets/Images/NavigationHelp/Mouse.svg +84 -0
  277. package/dist/cesium/Widgets/Images/NavigationHelp/MouseLeft.svg +76 -0
  278. package/dist/cesium/Widgets/Images/NavigationHelp/MouseMiddle.svg +76 -0
  279. package/dist/cesium/Widgets/Images/NavigationHelp/MouseRight.svg +76 -0
  280. package/dist/cesium/Widgets/Images/NavigationHelp/Touch.svg +120 -0
  281. package/dist/cesium/Widgets/Images/NavigationHelp/TouchDrag.svg +129 -0
  282. package/dist/cesium/Widgets/Images/NavigationHelp/TouchRotate.svg +76 -0
  283. package/dist/cesium/Widgets/Images/NavigationHelp/TouchTilt.svg +135 -0
  284. package/dist/cesium/Widgets/Images/NavigationHelp/TouchZoom.svg +74 -0
  285. package/dist/cesium/Widgets/Images/TerrainProviders/CesiumWorldTerrain.png +0 -0
  286. package/dist/cesium/Widgets/Images/TerrainProviders/Ellipsoid.png +0 -0
  287. package/dist/cesium/Widgets/Images/TimelineIcons.png +0 -0
  288. package/dist/cesium/Widgets/Images/info-loading.gif +0 -0
  289. package/dist/cesium/Widgets/InfoBox/InfoBox.css +92 -0
  290. package/dist/cesium/Widgets/InfoBox/InfoBoxDescription.css +178 -0
  291. package/dist/cesium/Widgets/NavigationHelpButton/NavigationHelpButton.css +93 -0
  292. package/dist/cesium/Widgets/NavigationHelpButton/lighter.css +38 -0
  293. package/dist/cesium/Widgets/PerformanceWatchdog/PerformanceWatchdog.css +15 -0
  294. package/dist/cesium/Widgets/ProjectionPicker/ProjectionPicker.css +38 -0
  295. package/dist/cesium/Widgets/SceneModePicker/SceneModePicker.css +56 -0
  296. package/dist/cesium/Widgets/SelectionIndicator/SelectionIndicator.css +20 -0
  297. package/dist/cesium/Widgets/Timeline/Timeline.css +103 -0
  298. package/dist/cesium/Widgets/Timeline/lighter.css +23 -0
  299. package/dist/cesium/Widgets/VRButton/VRButton.css +8 -0
  300. package/dist/cesium/Widgets/Viewer/Viewer.css +107 -0
  301. package/dist/cesium/Widgets/VoxelInspector/VoxelInspector.css +16 -0
  302. package/dist/cesium/Widgets/lighter.css +237 -0
  303. package/dist/cesium/Widgets/lighterShared.css +46 -0
  304. package/dist/cesium/Widgets/shared.css +103 -0
  305. package/dist/cesium/Widgets/widgets.css +1342 -0
  306. package/dist/cesium/Workers/chunk-23ZQ2IVV.js +29 -0
  307. package/dist/cesium/Workers/chunk-2EQO3Q56.js +26 -0
  308. package/dist/cesium/Workers/chunk-2MJIIVP4.js +26 -0
  309. package/dist/cesium/Workers/chunk-2TE5NTVD.js +26 -0
  310. package/dist/cesium/Workers/chunk-2ZBHLJST.js +26 -0
  311. package/dist/cesium/Workers/chunk-5TJMAQVL.js +26 -0
  312. package/dist/cesium/Workers/chunk-6BD4U3VO.js +26 -0
  313. package/dist/cesium/Workers/chunk-7TVGLKQF.js +26 -0
  314. package/dist/cesium/Workers/chunk-BTSYJ5XU.js +26 -0
  315. package/dist/cesium/Workers/chunk-BXMEEOCS.js +63 -0
  316. package/dist/cesium/Workers/chunk-BYLCY7GP.js +29 -0
  317. package/dist/cesium/Workers/chunk-CTHM3W6I.js +26 -0
  318. package/dist/cesium/Workers/chunk-CUUSNIVQ.js +26 -0
  319. package/dist/cesium/Workers/chunk-E3JOOS3S.js +26 -0
  320. package/dist/cesium/Workers/chunk-E7KYDCM5.js +26 -0
  321. package/dist/cesium/Workers/chunk-EDVBB7SS.js +27 -0
  322. package/dist/cesium/Workers/chunk-EFBN7QNX.js +26 -0
  323. package/dist/cesium/Workers/chunk-EQ4YRVWL.js +26 -0
  324. package/dist/cesium/Workers/chunk-F6PRE7D6.js +26 -0
  325. package/dist/cesium/Workers/chunk-FC4ZZ65J.js +26 -0
  326. package/dist/cesium/Workers/chunk-FFBVWF2L.js +26 -0
  327. package/dist/cesium/Workers/chunk-GBAA6GVX.js +26 -0
  328. package/dist/cesium/Workers/chunk-ICALLYLG.js +26 -0
  329. package/dist/cesium/Workers/chunk-ILRYTWTP.js +26 -0
  330. package/dist/cesium/Workers/chunk-IRNLBSEJ.js +26 -0
  331. package/dist/cesium/Workers/chunk-IX4VMHEV.js +26 -0
  332. package/dist/cesium/Workers/chunk-L6QHHACZ.js +26 -0
  333. package/dist/cesium/Workers/chunk-LI2ZSORM.js +26 -0
  334. package/dist/cesium/Workers/chunk-LSLE2RL4.js +26 -0
  335. package/dist/cesium/Workers/chunk-M4HLDBCG.js +26 -0
  336. package/dist/cesium/Workers/chunk-MJHHSGEH.js +26 -0
  337. package/dist/cesium/Workers/chunk-NMVKML6W.js +26 -0
  338. package/dist/cesium/Workers/chunk-OCWJRAXS.js +26 -0
  339. package/dist/cesium/Workers/chunk-OIRKANTH.js +26 -0
  340. package/dist/cesium/Workers/chunk-OIT7J4IC.js +26 -0
  341. package/dist/cesium/Workers/chunk-OLZ3FYUM.js +26 -0
  342. package/dist/cesium/Workers/chunk-Q5BPHJQF.js +26 -0
  343. package/dist/cesium/Workers/chunk-QFM5DCMQ.js +26 -0
  344. package/dist/cesium/Workers/chunk-QKUIYMGC.js +28 -0
  345. package/dist/cesium/Workers/chunk-S44JILQT.js +26 -0
  346. package/dist/cesium/Workers/chunk-SLT4J352.js +26 -0
  347. package/dist/cesium/Workers/chunk-SQMIIXB7.js +26 -0
  348. package/dist/cesium/Workers/chunk-TJ4XLGBQ.js +26 -0
  349. package/dist/cesium/Workers/chunk-TNSUQXWK.js +27 -0
  350. package/dist/cesium/Workers/chunk-UBOGZS7F.js +26 -0
  351. package/dist/cesium/Workers/chunk-V3OSTMM6.js +26 -0
  352. package/dist/cesium/Workers/chunk-V7QEYVP3.js +26 -0
  353. package/dist/cesium/Workers/chunk-VUKYSU4H.js +26 -0
  354. package/dist/cesium/Workers/chunk-W37FE5GR.js +26 -0
  355. package/dist/cesium/Workers/chunk-WBOV35NL.js +26 -0
  356. package/dist/cesium/Workers/chunk-WPMZLB3Y.js +26 -0
  357. package/dist/cesium/Workers/chunk-WWWZVEEH.js +26 -0
  358. package/dist/cesium/Workers/chunk-XFIQ5DEQ.js +28 -0
  359. package/dist/cesium/Workers/chunk-XQHLGIO7.js +26 -0
  360. package/dist/cesium/Workers/chunk-XUSCFAVF.js +26 -0
  361. package/dist/cesium/Workers/chunk-YP7I5QBZ.js +26 -0
  362. package/dist/cesium/Workers/chunk-Z3QF2EHT.js +26 -0
  363. package/dist/cesium/Workers/combineGeometry.js +26 -0
  364. package/dist/cesium/Workers/createBoxGeometry.js +26 -0
  365. package/dist/cesium/Workers/createBoxOutlineGeometry.js +26 -0
  366. package/dist/cesium/Workers/createCircleGeometry.js +26 -0
  367. package/dist/cesium/Workers/createCircleOutlineGeometry.js +26 -0
  368. package/dist/cesium/Workers/createCoplanarPolygonGeometry.js +26 -0
  369. package/dist/cesium/Workers/createCoplanarPolygonOutlineGeometry.js +26 -0
  370. package/dist/cesium/Workers/createCorridorGeometry.js +26 -0
  371. package/dist/cesium/Workers/createCorridorOutlineGeometry.js +26 -0
  372. package/dist/cesium/Workers/createCylinderGeometry.js +26 -0
  373. package/dist/cesium/Workers/createCylinderOutlineGeometry.js +26 -0
  374. package/dist/cesium/Workers/createEllipseGeometry.js +26 -0
  375. package/dist/cesium/Workers/createEllipseOutlineGeometry.js +26 -0
  376. package/dist/cesium/Workers/createEllipsoidGeometry.js +26 -0
  377. package/dist/cesium/Workers/createEllipsoidOutlineGeometry.js +26 -0
  378. package/dist/cesium/Workers/createFrustumGeometry.js +26 -0
  379. package/dist/cesium/Workers/createFrustumOutlineGeometry.js +26 -0
  380. package/dist/cesium/Workers/createGeometry.js +26 -0
  381. package/dist/cesium/Workers/createGroundPolylineGeometry.js +26 -0
  382. package/dist/cesium/Workers/createPlaneGeometry.js +26 -0
  383. package/dist/cesium/Workers/createPlaneOutlineGeometry.js +26 -0
  384. package/dist/cesium/Workers/createPolygonGeometry.js +26 -0
  385. package/dist/cesium/Workers/createPolygonOutlineGeometry.js +26 -0
  386. package/dist/cesium/Workers/createPolylineGeometry.js +26 -0
  387. package/dist/cesium/Workers/createPolylineVolumeGeometry.js +26 -0
  388. package/dist/cesium/Workers/createPolylineVolumeOutlineGeometry.js +26 -0
  389. package/dist/cesium/Workers/createRectangleGeometry.js +26 -0
  390. package/dist/cesium/Workers/createRectangleOutlineGeometry.js +26 -0
  391. package/dist/cesium/Workers/createSimplePolylineGeometry.js +26 -0
  392. package/dist/cesium/Workers/createSphereGeometry.js +26 -0
  393. package/dist/cesium/Workers/createSphereOutlineGeometry.js +26 -0
  394. package/dist/cesium/Workers/createTaskProcessorWorker.js +26 -0
  395. package/dist/cesium/Workers/createVectorTileClampedPolylines.js +26 -0
  396. package/dist/cesium/Workers/createVectorTileGeometries.js +26 -0
  397. package/dist/cesium/Workers/createVectorTilePoints.js +26 -0
  398. package/dist/cesium/Workers/createVectorTilePolygons.js +26 -0
  399. package/dist/cesium/Workers/createVectorTilePolylines.js +26 -0
  400. package/dist/cesium/Workers/createVerticesFromCesium3DTilesTerrain.js +26 -0
  401. package/dist/cesium/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +26 -0
  402. package/dist/cesium/Workers/createVerticesFromHeightmap.js +26 -0
  403. package/dist/cesium/Workers/createVerticesFromQuantizedTerrainMesh.js +26 -0
  404. package/dist/cesium/Workers/createWallGeometry.js +26 -0
  405. package/dist/cesium/Workers/createWallOutlineGeometry.js +26 -0
  406. package/dist/cesium/Workers/decodeDraco.js +26 -0
  407. package/dist/cesium/Workers/decodeGoogleEarthEnterprisePacket.js +26 -0
  408. package/dist/cesium/Workers/decodeI3S.js +26 -0
  409. package/dist/cesium/Workers/gaussianSplatSorter.js +26 -0
  410. package/dist/cesium/Workers/gaussianSplatTextureGenerator.js +26 -0
  411. package/dist/cesium/Workers/incrementallyBuildTerrainPicker.js +26 -0
  412. package/dist/cesium/Workers/transcodeKTX2.js +56 -0
  413. package/dist/cesium/Workers/transferTypedArrayTest.js +26 -0
  414. package/dist/cesium/Workers/upsampleQuantizedTerrainMesh.js +26 -0
  415. package/dist/cesium/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +26 -0
  416. package/dist/index.html +13 -10
  417. package/index.html +1 -0
  418. package/package.json +18 -15
  419. package/src/App.tsx +7 -9
  420. package/src/components/viewer/BCFPanel.tsx +46 -4
  421. package/src/components/viewer/CesiumOverlay.tsx +715 -0
  422. package/src/components/viewer/CesiumSettingsDialog.tsx +100 -0
  423. package/src/components/viewer/ChatPanel.tsx +232 -90
  424. package/src/components/viewer/CommandPalette.tsx +6 -1
  425. package/src/components/viewer/DesktopEntitlementBanner.tsx +74 -0
  426. package/src/components/viewer/ExportChangesButton.tsx +6 -1
  427. package/src/components/viewer/ExportDialog.tsx +22 -6
  428. package/src/components/viewer/HierarchyPanel.tsx +196 -0
  429. package/src/components/viewer/IDSPanel.tsx +52 -3
  430. package/src/components/viewer/KeyboardShortcutsDialog.tsx +1 -1
  431. package/src/components/viewer/MainToolbar.tsx +355 -28
  432. package/src/components/viewer/PropertiesPanel.tsx +234 -81
  433. package/src/components/viewer/ScriptPanel.tsx +34 -8
  434. package/src/components/viewer/SettingsPage.tsx +581 -0
  435. package/src/components/viewer/StatusBar.tsx +17 -1
  436. package/src/components/viewer/ThemeSwitch.tsx +63 -7
  437. package/src/components/viewer/ViewerLayout.tsx +48 -6
  438. package/src/components/viewer/Viewport.tsx +61 -8
  439. package/src/components/viewer/ViewportContainer.tsx +265 -28
  440. package/src/components/viewer/ViewportOverlays.tsx +132 -27
  441. package/src/components/viewer/bcf/BCFTopicDetail.tsx +4 -4
  442. package/src/components/viewer/chat/ModelSelector.tsx +90 -54
  443. package/src/components/viewer/properties/GeoreferencingPanel.tsx +229 -55
  444. package/src/components/viewer/properties/LocationMap.tsx +462 -19
  445. package/src/components/viewer/properties/ModelMetadataPanel.tsx +1 -1
  446. package/src/components/viewer/selectionHandlers.ts +4 -3
  447. package/src/components/viewer/tools/SectionCapControls.tsx +237 -0
  448. package/src/components/viewer/tools/SectionPanel.tsx +39 -18
  449. package/src/components/viewer/useAnimationLoop.ts +13 -1
  450. package/src/components/viewer/useGeometryStreaming.ts +127 -40
  451. package/src/components/viewer/useMouseControls.ts +4 -1
  452. package/src/components/viewer/useRenderUpdates.ts +1 -1
  453. package/src/hooks/ids/idsDataAccessor.ts +60 -24
  454. package/src/hooks/ingest/viewerModelIngest.ts +280 -0
  455. package/src/hooks/useIDS.ts +1 -1
  456. package/src/hooks/useIfc.ts +7 -1
  457. package/src/hooks/useIfcCache.ts +28 -15
  458. package/src/hooks/useIfcFederation.ts +378 -291
  459. package/src/hooks/useIfcLoader.ts +1657 -130
  460. package/src/hooks/useIfcServer.ts +0 -69
  461. package/src/hooks/useViewControls.ts +13 -5
  462. package/src/index.css +484 -10
  463. package/src/lib/desktop/desktopEntitlementEvents.ts +39 -0
  464. package/src/lib/desktop-entitlement.ts +43 -0
  465. package/src/lib/desktop-product.ts +124 -0
  466. package/src/lib/geo/cesium-bridge.ts +318 -0
  467. package/src/lib/geo/effective-georef.test.ts +73 -0
  468. package/src/lib/geo/effective-georef.ts +111 -0
  469. package/src/lib/geo/reproject.ts +249 -37
  470. package/src/lib/llm/byok-guard.test.ts +77 -0
  471. package/src/lib/llm/byok-guard.ts +39 -0
  472. package/src/lib/llm/free-models.test.ts +0 -6
  473. package/src/lib/llm/models.ts +104 -42
  474. package/src/lib/llm/stream-client.ts +74 -110
  475. package/src/lib/llm/stream-direct.test.ts +130 -0
  476. package/src/lib/llm/stream-direct.ts +316 -0
  477. package/src/lib/llm/types.ts +14 -2
  478. package/src/lib/recent-files.ts +2 -1
  479. package/src/main.tsx +1 -10
  480. package/src/services/analysis-extensions.ts +125 -0
  481. package/src/services/api-keys.ts +73 -0
  482. package/src/services/app-navigation.ts +13 -0
  483. package/src/services/bsdd.ts +53 -4
  484. package/src/services/cacheService.ts +1 -1
  485. package/src/services/desktop-cache.ts +43 -0
  486. package/src/services/desktop-export.ts +77 -0
  487. package/src/services/desktop-harness.ts +196 -0
  488. package/src/services/desktop-logger.ts +20 -0
  489. package/src/services/desktop-native-metadata.ts +207 -0
  490. package/src/services/desktop-panel-actions.ts +43 -0
  491. package/src/services/desktop-preferences.ts +44 -0
  492. package/src/services/file-dialog.ts +147 -0
  493. package/src/services/tauri-core-stub.ts +7 -0
  494. package/src/services/tauri-dialog-stub.ts +7 -0
  495. package/src/services/tauri-fs-stub.ts +7 -0
  496. package/src/store/constants.ts +20 -2
  497. package/src/store/index.ts +52 -7
  498. package/src/store/slices/cesiumSlice.ts +127 -0
  499. package/src/store/slices/chatSlice.test.ts +6 -76
  500. package/src/store/slices/chatSlice.ts +21 -58
  501. package/src/store/slices/dataSlice.ts +139 -28
  502. package/src/store/slices/desktopEntitlementSlice.ts +86 -0
  503. package/src/store/slices/loadingSlice.ts +14 -2
  504. package/src/store/slices/modelSlice.ts +58 -3
  505. package/src/store/slices/sectionSlice.test.ts +87 -7
  506. package/src/store/slices/sectionSlice.ts +151 -5
  507. package/src/store/slices/uiSlice.ts +28 -5
  508. package/src/store/types.ts +122 -2
  509. package/src/store.ts +1 -1
  510. package/src/utils/desktopModelSnapshot.ts +358 -0
  511. package/src/utils/ifcConfig.ts +6 -1
  512. package/src/utils/nativeSpatialDataStore.ts +253 -0
  513. package/src/utils/serverDataModel.ts +4 -0
  514. package/src/utils/spatialHierarchy.ts +10 -11
  515. package/src/utils/viewportUtils.ts +7 -2
  516. package/src/vite-env.d.ts +0 -4
  517. package/vite.config.ts +24 -0
  518. package/dist/assets/arrow-DJf2ErbF.js +0 -20
  519. package/dist/assets/basketViewActivator-aojwdomq.js +0 -1
  520. package/dist/assets/desktop-cache-oPzaWXYE.js +0 -1
  521. package/dist/assets/drawing-2d-gWfpdfYe.js +0 -257
  522. package/dist/assets/geometry.worker-Nz9_YIqh.js +0 -1
  523. package/dist/assets/ids-B4jTqB1O.js +0 -1
  524. package/dist/assets/ifc-lite_bg-eSkBTizQ.wasm +0 -0
  525. package/dist/assets/index-pbE7itQS.css +0 -1
  526. package/dist/assets/native-bridge-DSIyEYXG.js +0 -113
  527. package/dist/assets/wasm-bridge-B0J07fZZ.js +0 -1
  528. package/src/components/viewer/UpgradePage.tsx +0 -69
  529. package/src/lib/llm/ClerkChatSync.tsx +0 -74
  530. package/src/lib/llm/clerk-auth.ts +0 -62
@@ -0,0 +1,316 @@
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
+ * Direct browser-to-provider streaming for BYOK (Bring Your Own Key) models.
7
+ *
8
+ * Anthropic: Uses the official @anthropic-ai/sdk with `dangerouslyAllowBrowser`.
9
+ * OpenAI: Uses fetch against the OpenAI chat completions API (same SSE format
10
+ * the proxy already returns, so SSE parsing is shared).
11
+ *
12
+ * Keys are stored in localStorage and sent directly to the provider.
13
+ * They never pass through our server.
14
+ */
15
+
16
+ import Anthropic from '@anthropic-ai/sdk';
17
+ import { readSseStream, type StreamMessage, type StreamOptions } from './stream-client.js';
18
+
19
+ const STREAM_REQUEST_TIMEOUT_MS = 45_000;
20
+
21
+ // ── Anthropic ──────────────────────────────────────────────────────────────
22
+
23
+ type AnthropicMediaType = 'image/png' | 'image/jpeg' | 'image/gif' | 'image/webp';
24
+
25
+ type AnthropicContentBlock =
26
+ | { type: 'text'; text: string }
27
+ | { type: 'image'; source: { type: 'base64'; media_type: AnthropicMediaType; data: string } };
28
+
29
+ function toAnthropicMessages(
30
+ messages: StreamMessage[],
31
+ ): Array<{ role: 'user' | 'assistant'; content: string | AnthropicContentBlock[] }> {
32
+ return messages
33
+ .filter((m) => m.role === 'user' || m.role === 'assistant')
34
+ .map((m) => {
35
+ if (typeof m.content === 'string') {
36
+ return { role: m.role as 'user' | 'assistant', content: m.content };
37
+ }
38
+ // Multimodal content — convert OpenAI-style parts to Anthropic format
39
+ const blocks: AnthropicContentBlock[] = m.content.map((part) => {
40
+ if (part.type === 'text') {
41
+ return { type: 'text' as const, text: part.text };
42
+ }
43
+ // image_url → Anthropic image block
44
+ const dataUrl = part.image_url.url;
45
+ const match = dataUrl.match(/^data:(image\/[^;]+);base64,(.+)$/);
46
+ if (match) {
47
+ return {
48
+ type: 'image' as const,
49
+ source: {
50
+ type: 'base64' as const,
51
+ media_type: match[1] as AnthropicMediaType,
52
+ data: match[2],
53
+ },
54
+ };
55
+ }
56
+ // Fallback: pass URL as text
57
+ return { type: 'text' as const, text: `[Image: ${dataUrl.slice(0, 100)}]` };
58
+ });
59
+ return { role: m.role as 'user' | 'assistant', content: blocks };
60
+ });
61
+ }
62
+
63
+ export async function streamAnthropicChat(
64
+ apiKey: string,
65
+ options: Omit<StreamOptions, 'proxyUrl' | 'authToken' | 'onUsageInfo'>,
66
+ ): Promise<void> {
67
+ const { model, messages, system, signal, onChunk, onComplete, onError, onFinishReason } = options;
68
+
69
+ const client = new Anthropic({
70
+ apiKey,
71
+ dangerouslyAllowBrowser: true,
72
+ });
73
+
74
+ let fullText = '';
75
+ try {
76
+ const stream = client.messages.stream({
77
+ model,
78
+ max_tokens: 8192,
79
+ temperature: 0.3,
80
+ system: system || undefined,
81
+ messages: toAnthropicMessages(messages),
82
+ });
83
+
84
+ // Wire up abort signal
85
+ if (signal) {
86
+ const onAbort = () => stream.abort();
87
+ signal.addEventListener('abort', onAbort, { once: true });
88
+ stream.on('end', () => signal.removeEventListener('abort', onAbort));
89
+ }
90
+
91
+ stream.on('text', (text) => {
92
+ fullText += text;
93
+ onChunk(text);
94
+ });
95
+
96
+ const finalMessage = await stream.finalMessage();
97
+
98
+ if (signal?.aborted) return;
99
+
100
+ const stopReason = finalMessage.stop_reason;
101
+ onFinishReason?.(stopReason === 'end_turn' ? 'stop' : stopReason);
102
+ onComplete(fullText);
103
+ } catch (err) {
104
+ if (signal?.aborted) return;
105
+
106
+ if (err instanceof Anthropic.APIError) {
107
+ const msg = err.status === 401
108
+ ? 'Invalid Anthropic API key. Check your key in Settings.'
109
+ : err.status === 429
110
+ ? 'Anthropic rate limit reached. Please wait and try again.'
111
+ : `Anthropic error (${err.status}): ${err.message}`;
112
+ onError(new Error(msg));
113
+ } else {
114
+ onError(err instanceof Error ? err : new Error(String(err)));
115
+ }
116
+ }
117
+ }
118
+
119
+ // ── OpenAI ─────────────────────────────────────────────────────────────────
120
+
121
+ import { getModelById } from './models.js';
122
+
123
+ /**
124
+ * Stream an OpenAI model. Automatically picks the right API:
125
+ * - Chat Completions (`/v1/chat/completions`) for standard chat models
126
+ * - Responses (`/v1/responses`) for Codex-style models
127
+ */
128
+ export async function streamOpenAiChat(
129
+ apiKey: string,
130
+ options: Omit<StreamOptions, 'proxyUrl' | 'authToken' | 'onUsageInfo'>,
131
+ ): Promise<void> {
132
+ const modelDef = getModelById(options.model);
133
+ if (modelDef?.openaiApi === 'responses') {
134
+ return streamOpenAiResponses(apiKey, options);
135
+ }
136
+ return streamOpenAiChatCompletions(apiKey, options);
137
+ }
138
+
139
+ /** Standard Chat Completions API (GPT-5.4, GPT-5.4 Mini, etc.) */
140
+ async function streamOpenAiChatCompletions(
141
+ apiKey: string,
142
+ options: Omit<StreamOptions, 'proxyUrl' | 'authToken' | 'onUsageInfo'>,
143
+ ): Promise<void> {
144
+ const { model, messages, system, signal, onChunk, onComplete, onError, onFinishReason } = options;
145
+
146
+ const allMessages: StreamMessage[] = system
147
+ ? [{ role: 'system', content: system }, ...messages]
148
+ : [...messages];
149
+
150
+ const { response, cleanup } = await openAiFetch(
151
+ 'https://api.openai.com/v1/chat/completions',
152
+ {
153
+ model,
154
+ messages: allMessages.map((m) => ({ role: m.role, content: m.content })),
155
+ stream: true,
156
+ temperature: 0.3,
157
+ max_completion_tokens: 8192,
158
+ },
159
+ apiKey,
160
+ signal,
161
+ onError,
162
+ );
163
+ if (!response) return;
164
+
165
+ if (!response.body) { cleanup(); onError(new Error('No response body')); return; }
166
+
167
+ let fullText = '';
168
+ let finishReason: string | null = null;
169
+
170
+ const ok = await readSseStream(response.body, signal, (data) => {
171
+ const parsed = JSON.parse(data) as {
172
+ choices?: Array<{ delta?: { content?: string }; finish_reason?: string | null }>;
173
+ };
174
+ const content = parsed.choices?.[0]?.delta?.content;
175
+ if (content) { fullText += content; onChunk(content); }
176
+ const fr = parsed.choices?.[0]?.finish_reason;
177
+ if (fr) finishReason = fr;
178
+ }, onError);
179
+
180
+ cleanup();
181
+ if (ok) { onFinishReason?.(finishReason); onComplete(fullText); }
182
+ }
183
+
184
+ /** Responses API for Codex-style models (GPT-5.3 Codex) */
185
+ async function streamOpenAiResponses(
186
+ apiKey: string,
187
+ options: Omit<StreamOptions, 'proxyUrl' | 'authToken' | 'onUsageInfo'>,
188
+ ): Promise<void> {
189
+ const { model, messages, system, signal, onChunk, onComplete, onError, onFinishReason } = options;
190
+
191
+ // Build the input array: system instructions + conversation
192
+ const input: Array<{ role: string; content: string | unknown[] }> = [];
193
+ if (system) {
194
+ input.push({ role: 'developer', content: system });
195
+ }
196
+ for (const m of messages) {
197
+ input.push({ role: m.role, content: m.content });
198
+ }
199
+
200
+ const { response, cleanup } = await openAiFetch(
201
+ 'https://api.openai.com/v1/responses',
202
+ {
203
+ model,
204
+ input,
205
+ stream: true,
206
+ max_output_tokens: 8192,
207
+ },
208
+ apiKey,
209
+ signal,
210
+ onError,
211
+ );
212
+ if (!response) return;
213
+
214
+ if (!response.body) { cleanup(); onError(new Error('No response body')); return; }
215
+
216
+ let fullText = '';
217
+ // Map Responses API terminal events → chat-style finish_reason.
218
+ // `response.incomplete` is any non-completed terminal state: when the
219
+ // reason is `max_output_tokens` — or simply absent — map to 'length' so
220
+ // the ChatPanel "Continue" UX can resume a truncated Codex reply. Other
221
+ // explicit reasons (e.g. `content_filter`) pass through unchanged.
222
+ let finishReason: string | null = 'stop';
223
+
224
+ const ok = await readSseStream(response.body, signal, (data) => {
225
+ const event = JSON.parse(data) as {
226
+ type?: string;
227
+ delta?: string;
228
+ response?: {
229
+ status?: string;
230
+ incomplete_details?: { reason?: string } | null;
231
+ };
232
+ };
233
+ if (event.type === 'response.output_text.delta' && event.delta) {
234
+ fullText += event.delta;
235
+ onChunk(event.delta);
236
+ } else if (event.type === 'response.incomplete') {
237
+ const reason = event.response?.incomplete_details?.reason;
238
+ finishReason = reason == null || reason === 'max_output_tokens' ? 'length' : reason;
239
+ } else if (event.type === 'response.completed') {
240
+ finishReason = 'stop';
241
+ }
242
+ }, onError);
243
+
244
+ cleanup();
245
+ if (ok) { onFinishReason?.(finishReason); onComplete(fullText); }
246
+ }
247
+
248
+ // ── Shared helpers ─────────────────────────────────────────────────────────
249
+
250
+ async function openAiFetch(
251
+ url: string,
252
+ body: Record<string, unknown>,
253
+ apiKey: string,
254
+ signal: AbortSignal | undefined,
255
+ onError: (err: Error) => void,
256
+ ): Promise<{ response: Response | null; cleanup: () => void }> {
257
+ const controller = new AbortController();
258
+ const timeoutId = setTimeout(
259
+ () => controller.abort(new Error('Chat request timed out. Please try again.')),
260
+ STREAM_REQUEST_TIMEOUT_MS,
261
+ );
262
+ const abortFromParent = () => controller.abort(signal?.reason);
263
+ if (signal) {
264
+ if (signal.aborted) { clearTimeout(timeoutId); return { response: null, cleanup: () => {} }; }
265
+ signal.addEventListener('abort', abortFromParent, { once: true });
266
+ }
267
+
268
+ // cleanup() clears the connect timeout and removes the abort listener.
269
+ // Callers must call it AFTER streaming completes, not before — otherwise
270
+ // user cancellation during SSE consumption won't abort the fetch.
271
+ const cleanup = () => {
272
+ clearTimeout(timeoutId);
273
+ signal?.removeEventListener('abort', abortFromParent);
274
+ };
275
+
276
+ let response: Response;
277
+ try {
278
+ response = await fetch(url, {
279
+ method: 'POST',
280
+ headers: {
281
+ Authorization: `Bearer ${apiKey}`,
282
+ 'Content-Type': 'application/json',
283
+ },
284
+ body: JSON.stringify(body),
285
+ signal: controller.signal,
286
+ });
287
+ } catch (err) {
288
+ cleanup();
289
+ if (signal?.aborted) return { response: null, cleanup: () => {} };
290
+ if (controller.signal.aborted && controller.signal.reason instanceof Error) {
291
+ onError(controller.signal.reason);
292
+ } else {
293
+ onError(err instanceof Error ? err : new Error(String(err)));
294
+ }
295
+ return { response: null, cleanup: () => {} };
296
+ }
297
+
298
+ if (!response.ok) {
299
+ cleanup();
300
+ let detail = `OpenAI error (${response.status})`;
301
+ try {
302
+ const errBody = (await response.json()) as { error?: { message?: string } };
303
+ if (response.status === 401) {
304
+ detail = 'Invalid OpenAI API key. Check your key in the chat panel.';
305
+ } else if (response.status === 429) {
306
+ detail = 'OpenAI rate limit reached. Please wait and try again.';
307
+ } else if (errBody.error?.message) {
308
+ detail = `OpenAI: ${errBody.error.message}`;
309
+ }
310
+ } catch { /* ignore parse failure */ }
311
+ onError(new Error(detail));
312
+ return { response: null, cleanup: () => {} };
313
+ }
314
+
315
+ return { response, cleanup };
316
+ }
@@ -126,7 +126,15 @@ export interface FileAttachment {
126
126
  isImage?: boolean;
127
127
  }
128
128
 
129
- export type ModelTier = 'free' | 'pro';
129
+ export type ModelTier = 'free' | 'byok';
130
+
131
+ /**
132
+ * Where requests for this model are routed.
133
+ * - 'proxy': through the server-side proxy (free models)
134
+ * - 'anthropic': direct browser-to-Anthropic API (user's own key)
135
+ * - 'openai': direct browser-to-OpenAI API (user's own key)
136
+ */
137
+ export type ModelSource = 'proxy' | 'anthropic' | 'openai';
130
138
 
131
139
  /** Relative cost indicator for paid models */
132
140
  export type ModelCost = '$' | '$$' | '$$$';
@@ -136,6 +144,8 @@ export interface LLMModel {
136
144
  name: string;
137
145
  provider: string;
138
146
  tier: ModelTier;
147
+ /** Where requests are routed — proxy (free) or direct to provider (BYOK) */
148
+ source: ModelSource;
139
149
  contextWindow: number;
140
150
  /** Whether this model accepts image inputs in chat content */
141
151
  supportsImages: boolean;
@@ -143,8 +153,10 @@ export interface LLMModel {
143
153
  supportsFileAttachments: boolean;
144
154
  /** Notes shown in model selector */
145
155
  notes?: string;
146
- /** Relative cost indicator (pro models only) */
156
+ /** Relative cost indicator (BYOK models only) */
147
157
  cost?: ModelCost;
158
+ /** OpenAI API variant: 'chat' (default) or 'responses' (Codex-style models) */
159
+ openaiApi?: 'chat' | 'responses';
148
160
  }
149
161
 
150
162
  export type ChatStatus = 'idle' | 'sending' | 'streaming' | 'error';
@@ -103,7 +103,8 @@ export async function cacheFileBlobs(files: File[]): Promise<void> {
103
103
  }
104
104
 
105
105
  /** Retrieve a cached file blob and reconstruct a File object. */
106
- export async function getCachedFile(name: string): Promise<File | null> {
106
+ export async function getCachedFile(target: string | RecentFileEntry): Promise<File | null> {
107
+ const name = typeof target === 'string' ? target : target.name;
107
108
  try {
108
109
  const db = await openDB();
109
110
  const tx = db.transaction(STORE_NAME, 'readonly');
package/src/main.tsx CHANGED
@@ -8,21 +8,12 @@
8
8
 
9
9
  import React from 'react';
10
10
  import ReactDOM from 'react-dom/client';
11
- import { ClerkProvider } from '@clerk/clerk-react';
12
11
  import { App } from './App';
13
12
  import './index.css';
14
13
  import 'maplibre-gl/dist/maplibre-gl.css';
15
14
 
16
- const clerkPublishableKey = (import.meta.env.VITE_CLERK_PUBLISHABLE_KEY as string | undefined)?.trim();
17
-
18
15
  ReactDOM.createRoot(document.getElementById('root')!).render(
19
16
  <React.StrictMode>
20
- {clerkPublishableKey ? (
21
- <ClerkProvider publishableKey={clerkPublishableKey}>
22
- <App />
23
- </ClerkProvider>
24
- ) : (
25
- <App />
26
- )}
17
+ <App />
27
18
  </React.StrictMode>
28
19
  );
@@ -0,0 +1,125 @@
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 type { ComponentType, ReactNode } from 'react';
6
+
7
+ export type AnalysisExtensionPlacement = 'right' | 'bottom';
8
+
9
+ export interface AnalysisExtensionRenderProps {
10
+ onClose: () => void;
11
+ }
12
+
13
+ export interface AnalysisExtensionDefinition {
14
+ id: string;
15
+ label: string;
16
+ description?: string;
17
+ placement?: AnalysisExtensionPlacement;
18
+ icon: ComponentType<{ className?: string }>;
19
+ renderPanel: (props: AnalysisExtensionRenderProps) => ReactNode;
20
+ onBeforeOpen?: () => boolean | void;
21
+ }
22
+
23
+ export interface AnalysisExtensionsSnapshot {
24
+ activeId: string | null;
25
+ extensions: AnalysisExtensionDefinition[];
26
+ }
27
+
28
+ const listeners = new Set<() => void>();
29
+ const extensions = new Map<string, AnalysisExtensionDefinition>();
30
+
31
+ let activeId: string | null = null;
32
+ let snapshot: AnalysisExtensionsSnapshot = {
33
+ activeId,
34
+ extensions: [],
35
+ };
36
+
37
+ function rebuildSnapshot(): void {
38
+ snapshot = {
39
+ activeId,
40
+ extensions: Array.from(extensions.values()),
41
+ };
42
+ }
43
+
44
+ function emit(): void {
45
+ rebuildSnapshot();
46
+ listeners.forEach((listener) => listener());
47
+ }
48
+
49
+ function setActiveId(nextActiveId: string | null): void {
50
+ if (activeId === nextActiveId) {
51
+ return;
52
+ }
53
+ activeId = nextActiveId;
54
+ emit();
55
+ }
56
+
57
+ function canOpen(definition: AnalysisExtensionDefinition): boolean {
58
+ return definition.onBeforeOpen?.() !== false;
59
+ }
60
+
61
+ export function subscribeAnalysisExtensions(listener: () => void): () => void {
62
+ listeners.add(listener);
63
+ return () => {
64
+ listeners.delete(listener);
65
+ };
66
+ }
67
+
68
+ export function getAnalysisExtensionsSnapshot(): AnalysisExtensionsSnapshot {
69
+ return snapshot;
70
+ }
71
+
72
+ export function getAnalysisExtensionById(id: string | null | undefined): AnalysisExtensionDefinition | null {
73
+ if (!id) {
74
+ return null;
75
+ }
76
+ return extensions.get(id) ?? null;
77
+ }
78
+
79
+ export function closeActiveAnalysisExtension(): void {
80
+ setActiveId(null);
81
+ }
82
+
83
+ export function openAnalysisExtension(id: string): boolean {
84
+ const definition = extensions.get(id);
85
+ if (!definition) {
86
+ return false;
87
+ }
88
+ if (!canOpen(definition)) {
89
+ return false;
90
+ }
91
+ setActiveId(id);
92
+ return true;
93
+ }
94
+
95
+ export function toggleAnalysisExtension(id: string): boolean {
96
+ if (activeId === id) {
97
+ closeActiveAnalysisExtension();
98
+ return false;
99
+ }
100
+ return openAnalysisExtension(id);
101
+ }
102
+
103
+ export function registerAnalysisExtensions(definitions: AnalysisExtensionDefinition[]): () => void {
104
+ const nextEntries = definitions.map((definition) => [definition.id, definition] as const);
105
+ nextEntries.forEach(([id, definition]) => {
106
+ extensions.set(id, definition);
107
+ });
108
+ emit();
109
+
110
+ return () => {
111
+ let shouldEmit = false;
112
+ for (const [id] of nextEntries) {
113
+ if (extensions.delete(id)) {
114
+ shouldEmit = true;
115
+ }
116
+ if (activeId === id) {
117
+ activeId = null;
118
+ shouldEmit = true;
119
+ }
120
+ }
121
+ if (shouldEmit) {
122
+ emit();
123
+ }
124
+ };
125
+ }
@@ -0,0 +1,73 @@
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
+ * BYOK (Bring Your Own Key) API key storage.
7
+ *
8
+ * Stores user-provided API keys for Anthropic and OpenAI in localStorage.
9
+ * Keys are sent directly from the browser to the provider APIs — they never
10
+ * pass through our server proxy.
11
+ */
12
+
13
+ export interface ApiKeyConfig {
14
+ anthropicKey: string;
15
+ openaiKey: string;
16
+ }
17
+
18
+ const STORAGE_KEY = 'ifc-lite:api-keys:v1';
19
+ const CHANGED_EVENT = 'ifc-lite:api-keys-changed';
20
+
21
+ const EMPTY_CONFIG: ApiKeyConfig = {
22
+ anthropicKey: '',
23
+ openaiKey: '',
24
+ };
25
+
26
+ function sanitize(value: unknown): ApiKeyConfig {
27
+ const parsed = value && typeof value === 'object' ? (value as Partial<ApiKeyConfig>) : {};
28
+ return {
29
+ anthropicKey: typeof parsed.anthropicKey === 'string' ? parsed.anthropicKey.trim() : '',
30
+ openaiKey: typeof parsed.openaiKey === 'string' ? parsed.openaiKey.trim() : '',
31
+ };
32
+ }
33
+
34
+ export function getApiKeys(): ApiKeyConfig {
35
+ try {
36
+ return sanitize(JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '{}'));
37
+ } catch {
38
+ return { ...EMPTY_CONFIG };
39
+ }
40
+ }
41
+
42
+ export function updateApiKeys(updates: Partial<ApiKeyConfig>): ApiKeyConfig {
43
+ const next = { ...getApiKeys(), ...updates };
44
+ // Trim keys before saving
45
+ next.anthropicKey = next.anthropicKey.trim();
46
+ next.openaiKey = next.openaiKey.trim();
47
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(next));
48
+ window.dispatchEvent(new Event(CHANGED_EVENT));
49
+ return next;
50
+ }
51
+
52
+ export function clearApiKeys(): ApiKeyConfig {
53
+ localStorage.removeItem(STORAGE_KEY);
54
+ window.dispatchEvent(new Event(CHANGED_EVENT));
55
+ return { ...EMPTY_CONFIG };
56
+ }
57
+
58
+ export function subscribeApiKeys(listener: () => void): () => void {
59
+ window.addEventListener(CHANGED_EVENT, listener);
60
+ return () => window.removeEventListener(CHANGED_EVENT, listener);
61
+ }
62
+
63
+ export function hasAnthropicKey(): boolean {
64
+ return getApiKeys().anthropicKey.length > 0;
65
+ }
66
+
67
+ export function hasOpenaiKey(): boolean {
68
+ return getApiKeys().openaiKey.length > 0;
69
+ }
70
+
71
+ export function hasAnyApiKey(): boolean {
72
+ return hasAnthropicKey() || hasOpenaiKey();
73
+ }
@@ -0,0 +1,13 @@
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
+ export function navigateToPath(path: string, options: { replace?: boolean } = {}): void {
6
+ const { replace = false } = options;
7
+ if (replace) {
8
+ window.history.replaceState({}, '', path);
9
+ } else {
10
+ window.history.pushState({}, '', path);
11
+ }
12
+ window.dispatchEvent(new PopStateEvent('popstate'));
13
+ }
@@ -99,6 +99,40 @@ async function fetchJson<T>(url: string): Promise<T> {
99
99
  return res.json() as Promise<T>;
100
100
  }
101
101
 
102
+ interface BsddSearchApiResult {
103
+ uri?: string;
104
+ code?: string;
105
+ referenceCode?: string;
106
+ name?: string;
107
+ definition?: string | null;
108
+ dictionaryUri?: string;
109
+ }
110
+
111
+ function matchesIfcType(candidate: BsddSearchApiResult, ifcType: string): boolean {
112
+ return candidate.code === ifcType
113
+ || candidate.referenceCode === ifcType
114
+ || candidate.name === ifcType;
115
+ }
116
+
117
+ async function resolveFallbackClassUri(ifcType: string): Promise<string | null> {
118
+ try {
119
+ const raw = await fetchJson<{ classes?: BsddSearchApiResult[] }>(
120
+ `${BSDD_API}/api/Class/Search/v1?SearchText=${encodeURIComponent(ifcType)}&RelatedIfcEntities=${encodeURIComponent(ifcType)}`,
121
+ );
122
+ const classes = raw.classes ?? [];
123
+ if (classes.length === 0) return null;
124
+
125
+ const preferred = classes.find((entry) => entry.dictionaryUri === IFC_DICTIONARY_URI && matchesIfcType(entry, ifcType))
126
+ ?? classes.find((entry) => matchesIfcType(entry, ifcType))
127
+ ?? classes.find((entry) => entry.dictionaryUri === IFC_DICTIONARY_URI)
128
+ ?? classes[0];
129
+
130
+ return preferred?.uri ?? null;
131
+ } catch {
132
+ return null;
133
+ }
134
+ }
135
+
102
136
  // ---------------------------------------------------------------------------
103
137
  // Public API
104
138
  // ---------------------------------------------------------------------------
@@ -128,15 +162,30 @@ export function ifcClassUri(ifcType: string): string {
128
162
  export async function fetchClassInfo(
129
163
  ifcType: string,
130
164
  ): Promise<BsddClassInfo | null> {
131
- const uri = ifcClassUri(ifcType);
165
+ const defaultUri = ifcClassUri(ifcType);
166
+ let uri = defaultUri;
132
167
  const cached = getCached(uri);
133
168
  if (cached) return cached;
134
169
 
135
170
  try {
136
171
  // Parameter names must be PascalCase per the bSDD OpenAPI spec
137
- const raw = await fetchJson<Record<string, unknown>>(
138
- `${BSDD_API}/api/Class/v1?Uri=${encodeURIComponent(uri)}&IncludeClassProperties=true&IncludeClassRelations=true`,
139
- );
172
+ let raw: Record<string, unknown>;
173
+ try {
174
+ raw = await fetchJson<Record<string, unknown>>(
175
+ `${BSDD_API}/api/Class/v1?Uri=${encodeURIComponent(uri)}&IncludeClassProperties=true&IncludeClassRelations=true`,
176
+ );
177
+ } catch {
178
+ const fallbackUri = await resolveFallbackClassUri(ifcType);
179
+ if (!fallbackUri || fallbackUri === uri) {
180
+ throw new Error('bSDD class lookup failed');
181
+ }
182
+ uri = fallbackUri;
183
+ const fallbackCached = getCached(uri);
184
+ if (fallbackCached) return fallbackCached;
185
+ raw = await fetchJson<Record<string, unknown>>(
186
+ `${BSDD_API}/api/Class/v1?Uri=${encodeURIComponent(uri)}&IncludeClassProperties=true&IncludeClassRelations=true`,
187
+ );
188
+ }
140
189
 
141
190
  let info = mapClassResponse(raw, true);
142
191
 
@@ -71,7 +71,7 @@ let cacheService: ICacheService | null = null;
71
71
  export async function getCacheService(): Promise<ICacheService> {
72
72
  if (cacheService) return cacheService;
73
73
 
74
- if (isTauri) {
74
+ if (isTauri()) {
75
75
  // Desktop: Use Tauri native filesystem
76
76
  const mod = await import('./desktop-cache.js');
77
77
  cacheService = {