@geode/opengeodeweb-front 10.34.0-rc.8 → 10.34.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 (282) hide show
  1. package/{server → .build/server}/utils/app_config.js +10 -9
  2. package/{server → .build/server}/utils/cleanup.js +31 -17
  3. package/{server → .build/server}/utils/cloud.js +1 -4
  4. package/{server → .build/server}/utils/microservices.js +21 -9
  5. package/{server → .build/server}/utils/path.js +4 -4
  6. package/{server → .build/server}/utils/scripts.js +9 -9
  7. package/.build/server/utils/server_config.js +51 -0
  8. package/.build/server/utils/stream.js +6 -0
  9. package/{server → .build/server}/utils/ws_client.js +18 -3
  10. package/{shared → .build/shared}/scripts.js +10 -10
  11. package/.build/shared/utils/call_raw.js +31 -0
  12. package/{shared → .build/shared}/utils/call_schema.js +2 -2
  13. package/.build/shared/utils/fetch_raw.js +52 -0
  14. package/{shared → .build/shared}/utils/fetch_schema.js +2 -2
  15. package/{shared → .build/shared}/utils/file.js +3 -1
  16. package/{shared → .build/shared}/utils/response_handlers/load.js +10 -7
  17. package/{shared → .build/shared}/utils/validate_schema.js +1 -1
  18. package/app/components/ActionButton.vue +6 -6
  19. package/app/components/CameraManager/List.vue +5 -5
  20. package/app/components/CameraManager/Saver.vue +3 -5
  21. package/app/components/CameraManager.vue +6 -4
  22. package/app/components/CameraOrientation.vue +12 -12
  23. package/app/components/ClippingPlaneCard.vue +4 -2
  24. package/app/components/ClippingPlanes.vue +8 -8
  25. package/app/components/CrsSelector.vue +9 -10
  26. package/app/components/DeleteDialog.vue +4 -2
  27. package/app/components/DragAndDrop.vue +10 -12
  28. package/app/components/DragAndDropInternal/DragAndDropInline.vue +4 -2
  29. package/app/components/ExtensionSelector.vue +4 -4
  30. package/app/components/FeedBack/ErrorBanner.vue +3 -1
  31. package/app/components/FeedBack/Snackers.vue +4 -3
  32. package/app/components/FileSelector.vue +10 -8
  33. package/app/components/FileUploader.vue +11 -11
  34. package/app/components/GlassCard.vue +1 -1
  35. package/app/components/HybridRenderingView.vue +7 -5
  36. package/app/components/HybridViewerTooltip.vue +7 -7
  37. package/app/components/Launcher.vue +1 -1
  38. package/app/components/Loading/EcoMessages.vue +9 -3
  39. package/app/components/Loading.vue +2 -2
  40. package/app/components/MissingFilesSelector.vue +12 -10
  41. package/app/components/ObjectSelector.vue +10 -9
  42. package/app/components/PackagesVersions.vue +6 -5
  43. package/app/components/Recaptcha.vue +3 -3
  44. package/app/components/RemoteRenderingView.vue +6 -7
  45. package/app/components/Ruler.vue +3 -3
  46. package/app/components/Screenshot.vue +6 -6
  47. package/app/components/SearchBar.vue +4 -2
  48. package/app/components/ShrinkFilter.vue +7 -7
  49. package/app/components/Step.vue +6 -5
  50. package/app/components/Stepper.vue +4 -3
  51. package/app/components/ToolPanel.vue +6 -3
  52. package/app/components/ViewToolbar.vue +25 -28
  53. package/app/components/Viewer/ContextMenu/CenterButton.vue +7 -5
  54. package/app/components/Viewer/ContextMenu/CircularItems.vue +3 -3
  55. package/app/components/Viewer/ContextMenu/ContextMenu.vue +22 -19
  56. package/app/components/Viewer/ContextMenu/ContextMenuItem.vue +10 -8
  57. package/app/components/Viewer/ContextMenu/InfoCard.vue +11 -12
  58. package/app/components/Viewer/EdgedCurve/SpecificEdgesOptions.vue +13 -17
  59. package/app/components/Viewer/Generic/Mesh/CellsOptions.vue +11 -15
  60. package/app/components/Viewer/Generic/Mesh/EdgesOptions.vue +12 -16
  61. package/app/components/Viewer/Generic/Mesh/PointsOptions.vue +8 -12
  62. package/app/components/Viewer/Generic/Mesh/PolygonsOptions.vue +11 -15
  63. package/app/components/Viewer/Generic/Mesh/PolyhedraOptions.vue +11 -15
  64. package/app/components/Viewer/Generic/Model/BlocksOptions.vue +67 -38
  65. package/app/components/Viewer/Generic/Model/CornersOptions.vue +53 -23
  66. package/app/components/Viewer/Generic/Model/EdgesOptions.vue +1 -3
  67. package/app/components/Viewer/Generic/Model/LinesOptions.vue +67 -38
  68. package/app/components/Viewer/Generic/Model/ModelStyleCard.vue +31 -15
  69. package/app/components/Viewer/Generic/Model/ModelStyleOptions.vue +2 -3
  70. package/app/components/Viewer/Generic/Model/PointsOptions.vue +6 -6
  71. package/app/components/Viewer/Generic/Model/SurfacesOptions.vue +69 -38
  72. package/app/components/Viewer/ObjectTree/Base/CommonTreeView.vue +64 -46
  73. package/app/components/Viewer/ObjectTree/Base/Controls.vue +5 -5
  74. package/app/components/Viewer/ObjectTree/Base/ItemLabel.vue +13 -9
  75. package/app/components/Viewer/ObjectTree/Base/StickyHeader.vue +5 -5
  76. package/app/components/Viewer/ObjectTree/Base/TreeRow.vue +10 -10
  77. package/app/components/Viewer/ObjectTree/Box.vue +6 -4
  78. package/app/components/Viewer/ObjectTree/Layout.vue +23 -21
  79. package/app/components/Viewer/ObjectTree/Views/GlobalObjects.vue +14 -14
  80. package/app/components/Viewer/ObjectTree/Views/{ModelCollections.vue → ModelTree.vue} +59 -24
  81. package/app/components/Viewer/Options/AttributeColorBar.vue +4 -2
  82. package/app/components/Viewer/Options/AttributeRangeSelector.vue +4 -2
  83. package/app/components/Viewer/Options/AttributeSelector.vue +7 -9
  84. package/app/components/Viewer/Options/ColorMapList.vue +15 -13
  85. package/app/components/Viewer/Options/ColorMapPicker.vue +4 -4
  86. package/app/components/Viewer/Options/ColorPicker.vue +223 -41
  87. package/app/components/Viewer/Options/ColoringTypeSelector.vue +16 -16
  88. package/app/components/Viewer/Options/ColormapQuickPicker.vue +7 -5
  89. package/app/components/Viewer/Options/OptionsSection.vue +1 -1
  90. package/app/components/Viewer/Options/TextureItem.vue +8 -6
  91. package/app/components/Viewer/Options/TexturesSelector.vue +1 -1
  92. package/app/components/Viewer/OverlappingObjectsPicker.vue +8 -9
  93. package/app/components/Viewer/PointSet/SpecificPointsOptions.vue +2 -6
  94. package/app/components/Viewer/Solid/SpecificPolyhedraOptions.vue +12 -16
  95. package/app/components/Viewer/Surface/PolygonsOptions.vue +12 -16
  96. package/app/components/Viewer/Ui.vue +2 -2
  97. package/app/components/Wrapper.vue +1 -4
  98. package/app/components/ZScaling.vue +5 -3
  99. package/app/components/csv-preview/CsvPreviewer.vue +38 -37
  100. package/app/components/csv-preview/CsvSettings.vue +6 -4
  101. package/app/components/csv-preview/CsvTable.vue +1 -1
  102. package/app/composables/batch_style.ts +5 -6
  103. package/app/composables/clipping_planes_widget.ts +73 -181
  104. package/app/composables/clipping_planes_widget_entries.ts +189 -0
  105. package/app/composables/copy_to_clipboard.ts +7 -0
  106. package/app/composables/global_attribute_style.ts +163 -83
  107. package/app/composables/hover_highlight.ts +46 -14
  108. package/app/composables/model_collections.ts +26 -13
  109. package/app/composables/model_components.ts +26 -13
  110. package/app/composables/project_manager.ts +76 -19
  111. package/app/composables/responsive_middle_truncate.ts +13 -13
  112. package/app/composables/stepper_tree.ts +34 -11
  113. package/app/composables/tree_filter.ts +66 -44
  114. package/app/composables/tree_keyboard_nav.ts +25 -11
  115. package/app/composables/tree_scroll.ts +44 -14
  116. package/app/composables/use_adaptive_styles.ts +66 -23
  117. package/app/composables/use_overlapping_picker.ts +66 -16
  118. package/app/composables/use_quick_colormap.ts +16 -5
  119. package/app/composables/virtual_tree.ts +75 -43
  120. package/app/composables/vtk_implicit_plane_widget.d.ts +2 -0
  121. package/app/plugins/auto_store_register.ts +2 -7
  122. package/app/plugins/click_outside_ignore_snackbars.client.ts +39 -0
  123. package/app/stores/app.ts +57 -192
  124. package/app/stores/app_helpers/extension.ts +179 -0
  125. package/app/stores/back.ts +37 -21
  126. package/app/stores/camera_manager.ts +22 -20
  127. package/app/stores/cloud.ts +17 -13
  128. package/app/stores/data.ts +88 -47
  129. package/app/stores/data_helpers/collections.ts +36 -38
  130. package/app/stores/data_helpers/mesh.ts +45 -36
  131. package/app/stores/data_style.ts +50 -28
  132. package/app/stores/feedback.ts +6 -6
  133. package/app/stores/hybrid_viewer.ts +41 -52
  134. package/app/stores/infra.ts +39 -37
  135. package/app/stores/menu.ts +23 -14
  136. package/app/stores/treeview.ts +72 -42
  137. package/app/stores/viewer.ts +39 -27
  138. package/app/utils/attributes.ts +3 -3
  139. package/app/utils/clipping_planes.ts +111 -14
  140. package/app/utils/color_picker.ts +57 -0
  141. package/app/utils/colormap.ts +58 -35
  142. package/app/utils/default_styles/index.ts +2 -2
  143. package/app/utils/default_styles/meshes.ts +107 -13
  144. package/app/utils/default_styles/models.ts +83 -14
  145. package/app/utils/extension.ts +47 -20
  146. package/app/utils/import_workflow.ts +21 -13
  147. package/app/utils/name_cleaner.ts +1 -1
  148. package/app/utils/string.ts +1 -1
  149. package/app/utils/treeview.ts +2 -2
  150. package/internal/database/base_database.ts +7 -3
  151. package/internal/database/database.ts +36 -26
  152. package/internal/database/extended_database.ts +1 -1
  153. package/internal/stores/data_style/mesh/cells/cell.ts +70 -34
  154. package/internal/stores/data_style/mesh/cells/color.ts +12 -6
  155. package/internal/stores/data_style/mesh/cells/common.ts +18 -8
  156. package/internal/stores/data_style/mesh/cells/index.ts +122 -42
  157. package/internal/stores/data_style/mesh/cells/textures.ts +12 -6
  158. package/internal/stores/data_style/mesh/cells/vertex.ts +75 -34
  159. package/internal/stores/data_style/mesh/cells/visibility.ts +15 -4
  160. package/internal/stores/data_style/mesh/edges/color.ts +12 -6
  161. package/internal/stores/data_style/mesh/edges/common.ts +14 -6
  162. package/internal/stores/data_style/mesh/edges/edge.ts +71 -39
  163. package/internal/stores/data_style/mesh/edges/index.ts +117 -42
  164. package/internal/stores/data_style/mesh/edges/vertex.ts +76 -39
  165. package/internal/stores/data_style/mesh/edges/visibility.ts +15 -4
  166. package/internal/stores/data_style/mesh/edges/width.ts +12 -4
  167. package/internal/stores/data_style/mesh/index.ts +30 -11
  168. package/internal/stores/data_style/mesh/points/color.ts +12 -6
  169. package/internal/stores/data_style/mesh/points/common.ts +21 -8
  170. package/internal/stores/data_style/mesh/points/index.ts +101 -50
  171. package/internal/stores/data_style/mesh/points/size.ts +12 -4
  172. package/internal/stores/data_style/mesh/points/vertex.ts +75 -34
  173. package/internal/stores/data_style/mesh/points/visibility.ts +17 -7
  174. package/internal/stores/data_style/mesh/polygons/color.ts +12 -6
  175. package/internal/stores/data_style/mesh/polygons/common.ts +23 -6
  176. package/internal/stores/data_style/mesh/polygons/index.ts +130 -70
  177. package/internal/stores/data_style/mesh/polygons/polygon.ts +77 -43
  178. package/internal/stores/data_style/mesh/polygons/textures.ts +12 -6
  179. package/internal/stores/data_style/mesh/polygons/vertex.ts +79 -39
  180. package/internal/stores/data_style/mesh/polygons/visibility.ts +16 -6
  181. package/internal/stores/data_style/mesh/polyhedra/color.ts +12 -6
  182. package/internal/stores/data_style/mesh/polyhedra/common.ts +14 -6
  183. package/internal/stores/data_style/mesh/polyhedra/index.ts +115 -56
  184. package/internal/stores/data_style/mesh/polyhedra/polyhedron.ts +80 -39
  185. package/internal/stores/data_style/mesh/polyhedra/vertex.ts +79 -39
  186. package/internal/stores/data_style/mesh/polyhedra/visibility.ts +16 -6
  187. package/internal/stores/data_style/model/blocks/color.ts +43 -13
  188. package/internal/stores/data_style/model/blocks/common.ts +21 -6
  189. package/internal/stores/data_style/model/blocks/index.ts +89 -59
  190. package/internal/stores/data_style/model/blocks/polyhedron.ts +101 -44
  191. package/internal/stores/data_style/model/blocks/vertex.ts +107 -42
  192. package/internal/stores/data_style/model/blocks/visibility.ts +17 -4
  193. package/internal/stores/data_style/model/color.ts +171 -83
  194. package/internal/stores/data_style/model/common.ts +70 -21
  195. package/internal/stores/data_style/model/corners/color.ts +43 -11
  196. package/internal/stores/data_style/model/corners/common.ts +25 -6
  197. package/internal/stores/data_style/model/corners/index.ts +66 -41
  198. package/internal/stores/data_style/model/corners/vertex.ts +105 -74
  199. package/internal/stores/data_style/model/corners/visibility.ts +19 -4
  200. package/internal/stores/data_style/model/edges/common.ts +12 -4
  201. package/internal/stores/data_style/model/edges/index.ts +2 -1
  202. package/internal/stores/data_style/model/edges/visibility.ts +24 -7
  203. package/internal/stores/data_style/model/index.ts +24 -11
  204. package/internal/stores/data_style/model/lines/color.ts +41 -11
  205. package/internal/stores/data_style/model/lines/common.ts +17 -6
  206. package/internal/stores/data_style/model/lines/edge.ts +105 -42
  207. package/internal/stores/data_style/model/lines/index.ts +86 -59
  208. package/internal/stores/data_style/model/lines/vertex.ts +105 -42
  209. package/internal/stores/data_style/model/lines/visibility.ts +17 -4
  210. package/internal/stores/data_style/model/points/common.ts +8 -4
  211. package/internal/stores/data_style/model/points/index.ts +10 -3
  212. package/internal/stores/data_style/model/points/size.ts +12 -4
  213. package/internal/stores/data_style/model/points/visibility.ts +16 -6
  214. package/internal/stores/data_style/model/selection.ts +80 -58
  215. package/internal/stores/data_style/model/surfaces/color.ts +41 -11
  216. package/internal/stores/data_style/model/surfaces/common.ts +23 -6
  217. package/internal/stores/data_style/model/surfaces/index.ts +89 -59
  218. package/internal/stores/data_style/model/surfaces/polygon.ts +107 -67
  219. package/internal/stores/data_style/model/surfaces/vertex.ts +111 -67
  220. package/internal/stores/data_style/model/surfaces/visibility.ts +18 -5
  221. package/internal/stores/data_style/model/visibility.ts +82 -20
  222. package/internal/stores/data_style/state.ts +77 -65
  223. package/internal/stores/hybrid_viewer/brightness.ts +49 -31
  224. package/internal/stores/hybrid_viewer/camera.ts +191 -177
  225. package/internal/stores/hybrid_viewer/camera_animation.ts +11 -10
  226. package/internal/stores/hybrid_viewer/core.ts +64 -0
  227. package/internal/stores/hybrid_viewer/filters.ts +10 -16
  228. package/internal/stores/hybrid_viewer/highlight.ts +91 -130
  229. package/internal/stores/hybrid_viewer/ruler.ts +24 -15
  230. package/internal/stores/hybrid_viewer/scene.ts +96 -117
  231. package/internal/stores/hybrid_viewer/viewport.ts +74 -65
  232. package/internal/stores/hybrid_viewer/vtk_types.ts +13 -29
  233. package/internal/utils/api_fetch.ts +54 -23
  234. package/internal/utils/upload_file.ts +74 -53
  235. package/internal/utils/viewer_call.ts +22 -13
  236. package/internal/utils/ws_client.ts +24 -13
  237. package/nuxt.config.ts +58 -1
  238. package/package.json +20 -8
  239. package/server/api/cloud/extensions/run.post.ts +6 -10
  240. package/server/api/local/app/project_folder_path.post.ts +4 -4
  241. package/server/api/local/app/run_back.post.ts +5 -7
  242. package/server/api/local/app/run_viewer.post.ts +5 -7
  243. package/server/api/local/extensions/kill.post.ts +4 -3
  244. package/server/api/local/extensions/run.post.ts +7 -10
  245. package/server/api/local/extensions/upload.put.ts +44 -54
  246. package/server/api/microservice/app/get_is_app_ready.get.ts +4 -5
  247. package/server/api/microservice/app/set_app_base_url.post.ts +5 -6
  248. package/server/api/microservice/app/set_back_base_url.post.ts +5 -6
  249. package/server/api/microservice/app/set_is_app_ready.post.ts +5 -6
  250. package/server/api/microservice/app/set_viewer_base_url.post.ts +5 -6
  251. package/server/api/microservice/extensions/download.post.ts +5 -4
  252. package/server/api/serverless/run_cloud.post.ts +53 -11
  253. package/server/utils/app_config.ts +29 -22
  254. package/server/utils/cleanup.ts +60 -30
  255. package/server/utils/cloud.ts +9 -8
  256. package/server/utils/extension.ts +23 -9
  257. package/server/utils/microservices.ts +33 -24
  258. package/server/utils/path.ts +4 -4
  259. package/server/utils/scripts.ts +26 -23
  260. package/server/utils/server.ts +2 -2
  261. package/server/utils/server_config.ts +41 -27
  262. package/server/utils/stream.ts +6 -0
  263. package/server/utils/ws_client.ts +42 -8
  264. package/shared/scripts.ts +15 -10
  265. package/shared/utils/call_raw.ts +23 -16
  266. package/shared/utils/call_schema.ts +5 -8
  267. package/shared/utils/fetch_raw.ts +87 -47
  268. package/shared/utils/fetch_schema.ts +6 -9
  269. package/shared/utils/file.ts +8 -2
  270. package/shared/utils/response_handlers/load.ts +26 -11
  271. package/shared/utils/types.ts +9 -9
  272. package/shared/utils/validate_schema.ts +1 -1
  273. package/app/components/Viewer/ObjectTree/Views/ModelComponents.vue +0 -276
  274. package/server/types/vendor.d.ts +0 -64
  275. package/server/utils/server_config.js +0 -43
  276. package/shared/utils/call_raw.js +0 -30
  277. package/shared/utils/fetch_raw.js +0 -40
  278. /package/{opengeodeweb_front_schemas.js → .build/opengeodeweb_front_schemas.js} +0 -0
  279. /package/{server → .build/server}/utils/server.js +0 -0
  280. /package/{shared → .build/shared}/app_mode.js +0 -0
  281. /package/{shared → .build/shared}/utils/parse_boolean.js +0 -0
  282. /package/{shared → .build/shared}/utils/types.js +0 -0
package/app/stores/app.ts CHANGED
@@ -1,11 +1,9 @@
1
- // This file grew past the 310-line limit purely from added type annotations/interfaces during the TypeScript migration, with no new logic.
2
- // oxlint-disable eslint/max-lines
3
1
  // Local imports
4
2
  import { getRestApiPort, getRestApiProtocol, isCloudMode } from "@ogw_front/utils/stores.js";
5
3
  import { Status } from "@ogw_front/utils/status";
6
4
  import { api_fetch } from "@ogw_internal/utils/api_fetch.js";
7
- import { killExtension } from "@ogw_front/utils/extension.js";
8
5
  import { upload_file } from "@ogw_internal/utils/upload_file.js";
6
+ import { useAppExtensions } from "./app_helpers/extension.js";
9
7
  import { useInfraStore } from "@ogw_front/stores/infra";
10
8
 
11
9
  import type { JsonRpcSchema, RequestHandlers } from "@ogw_shared/utils/types.js";
@@ -27,31 +25,11 @@ interface RegisterableStore {
27
25
  $patch?: (partial: Record<string, unknown>) => void;
28
26
  exportStores?: (params?: Record<string, unknown>) => Promise<unknown>;
29
27
  importStores?: (snapshot: unknown) => Promise<void> | void;
28
+ connect?: () => Promise<void>;
29
+ kill?: () => Promise<void>;
30
30
  [key: string]: unknown;
31
31
  }
32
32
 
33
- interface ExtensionMetadata {
34
- id: string;
35
- store: () => RegisterableStore;
36
- [key: string]: unknown;
37
- }
38
-
39
- interface ExtensionModule {
40
- metadata: ExtensionMetadata;
41
- install: (api: unknown, backendPath?: string) => Promise<void>;
42
- [key: string]: unknown;
43
- }
44
-
45
- interface ExtensionData {
46
- module: ExtensionModule;
47
- id: string;
48
- path: string;
49
- backendPath: string | undefined;
50
- loadedAt: string;
51
- metadata: ExtensionMetadata;
52
- enabled: boolean;
53
- }
54
-
55
33
  // oxlint-disable-next-line max-lines-per-function, max-statements
56
34
  export const useAppStore = defineStore("app", () => {
57
35
  const stores: RegisterableStore[] = [];
@@ -79,9 +57,6 @@ export const useAppStore = defineStore("app", () => {
79
57
  globalComponents.value.set(extensionId, new Map());
80
58
  }
81
59
  globalComponents.value.get(extensionId)?.set(componentId, component);
82
- console.log(
83
- `[AppStore] Registered global component ${componentId} for extension ${extensionId}`,
84
- );
85
60
  }
86
61
 
87
62
  function unregisterGlobalComponent(extensionId: string, componentId: string): void {
@@ -91,12 +66,12 @@ export const useAppStore = defineStore("app", () => {
91
66
  }
92
67
 
93
68
  function registerStore(store: RegisterableStore): void {
94
- const isAlreadyRegistered = stores.some((registeredStore) => registeredStore.$id === store.$id);
69
+ const isAlreadyRegistered = stores.some(
70
+ (registeredStore: RegisterableStore) => registeredStore.$id === store.$id,
71
+ );
95
72
  if (isAlreadyRegistered) {
96
- console.log(`[AppStore] Store "${store.$id}" already registered, skipping`);
97
73
  return;
98
74
  }
99
- console.log("[AppStore] Registering store", store.$id);
100
75
  stores.push(store);
101
76
  }
102
77
 
@@ -104,212 +79,106 @@ export const useAppStore = defineStore("app", () => {
104
79
  params: Record<string, unknown> = {},
105
80
  ): Promise<Record<string, unknown>> {
106
81
  const snapshot: Record<string, unknown> = {};
107
- let exportCount = 0;
108
82
 
109
- console.log(`[AppStore] Exporting stores, total registered: ${stores.length}`);
110
83
  await Promise.all(
111
- stores.map(async (store) => {
84
+ stores.map(async (store: RegisterableStore) => {
112
85
  if (!store.exportStores) {
113
86
  return;
114
87
  }
115
88
  const storeId = store.$id;
116
89
  try {
117
90
  snapshot[storeId] = await store.exportStores(params);
118
- exportCount += 1;
119
- } catch (error) {
120
- console.error(`[AppStore] Error exporting store "${storeId}":`, error);
91
+ } catch {
92
+ // Ignore stores that fail to export; other stores still complete independently.
121
93
  }
122
94
  }),
123
95
  );
124
- console.log(`[AppStore] Exported ${exportCount} stores; snapshot keys:`, Object.keys(snapshot));
125
96
  return snapshot;
126
97
  }
127
98
 
128
99
  async function importStores(snapshot: Record<string, unknown> | undefined): Promise<void> {
129
100
  if (!snapshot) {
130
- console.warn("[AppStore] import called with invalid snapshot");
131
101
  return;
132
102
  }
133
- console.log("[AppStore] Import snapshot keys:", Object.keys(snapshot || {}));
134
103
 
135
- let importedCount = 0;
136
- const notFoundStores: string[] = [];
104
+ const missingStoreIds: string[] = [];
105
+
137
106
  await Promise.all(
138
- stores.map(async (store) => {
107
+ stores.map(async (store: RegisterableStore) => {
139
108
  if (!store.importStores) {
140
109
  return;
141
110
  }
142
111
  const storeId = store.$id;
143
- if (!snapshot[storeId]) {
144
- notFoundStores.push(storeId);
112
+ if (snapshot[storeId] === undefined) {
113
+ missingStoreIds.push(storeId);
145
114
  return;
146
115
  }
147
116
  try {
148
117
  await store.importStores(snapshot[storeId]);
149
- importedCount += 1;
150
- } catch (error) {
151
- console.error(`[AppStore] Error importing store "${storeId}":`, error);
118
+ } catch {
119
+ // Ignore stores that fail to import; other stores still complete independently.
152
120
  }
153
121
  }),
154
122
  );
155
- if (notFoundStores.length > 0) {
156
- console.warn(`[AppStore] Stores not found in snapshot: ${notFoundStores.join(", ")}`);
157
- }
158
- console.log(`[AppStore] Imported ${importedCount} stores`);
159
- }
160
-
161
- const loadedExtensions = ref<Map<string, ExtensionData>>(new Map());
162
- const extensionAPI = ref<unknown>(undefined);
163
- const codeTransformer = ref<((code: string) => string) | undefined>(undefined);
164
-
165
- function setExtensionAPI(api: unknown): void {
166
- extensionAPI.value = api;
167
- }
168
-
169
- function setCodeTransformer(transformer: (code: string) => string): void {
170
- codeTransformer.value = transformer;
171
- }
172
123
 
173
- function getExtension(id: string): ExtensionData | undefined {
174
- return loadedExtensions.value.get(id);
175
- }
176
-
177
- async function loadExtension(
178
- path: string,
179
- extensionPort: string,
180
- backendPath: string | undefined = undefined,
181
- ): Promise<ExtensionModule> {
182
- try {
183
- let finalURL = path;
184
-
185
- if (codeTransformer.value && path.startsWith("blob:")) {
186
- const response = await fetch(path);
187
- const code = await response.text();
188
- const transformedCode = codeTransformer.value(code);
189
-
190
- const newBlob = new Blob([transformedCode], {
191
- type: "application/javascript",
192
- });
193
- finalURL = URL.createObjectURL(newBlob);
194
- }
195
- // oxlint-disable-next-line no-inline-comments
196
- const extensionModule: ExtensionModule = await import(/* @vite-ignore */ finalURL);
197
- const store = extensionModule.metadata.store();
198
- store.$patch?.({ default_local_port: extensionPort });
199
-
200
- if (finalURL !== path && finalURL.startsWith("blob:")) {
201
- URL.revokeObjectURL(finalURL);
202
- }
203
-
204
- if (!extensionModule.metadata?.id) {
205
- throw new Error("Extension must have metadata.id");
206
- }
207
-
208
- const extensionId = extensionModule.metadata.id;
209
-
210
- if (loadedExtensions.value.has(extensionId)) {
211
- console.warn(`[AppStore] Extension "${extensionId}" is already loaded`);
212
- throw new Error(`Extension "${extensionId}" is already loaded.`);
213
- }
214
-
215
- if (!extensionAPI.value) {
216
- throw new Error("Extension API not initialized");
217
- }
218
-
219
- if (typeof extensionModule.install !== "function") {
220
- throw new TypeError("Extension must export an install function");
221
- }
222
-
223
- await extensionModule.install(extensionAPI.value, backendPath);
224
-
225
- const extensionData: ExtensionData = {
226
- module: extensionModule,
227
- id: extensionId,
228
- path,
229
- backendPath,
230
- loadedAt: new Date().toISOString(),
231
- metadata: extensionModule.metadata,
232
- enabled: true,
233
- };
234
- loadedExtensions.value.set(extensionId, extensionData);
235
-
236
- console.log(`[AppStore] Extension loaded successfully: ${extensionId}`);
237
- return extensionModule;
238
- } catch (error) {
239
- console.error(`[AppStore] Failed to load extension from ${path}:`, error);
240
- throw error;
124
+ if (missingStoreIds.length > 0) {
125
+ console.warn(`Stores not found in snapshot: ${missingStoreIds.join(", ")}`);
241
126
  }
242
127
  }
243
128
 
244
- function getLoadedExtensions(): ExtensionData[] {
245
- return [...loadedExtensions.value.values()];
246
- }
247
-
248
- async function unloadExtension(extensionId: string): Promise<boolean> {
249
- console.log(`[AppStore] Unloading extension: ${extensionId}`);
250
- const infraStore = useInfraStore();
251
- await infraStore.unregister_microservice(extensionId);
252
- await killExtension(extensionId);
253
-
254
- loadedExtensions.value.delete(extensionId);
255
- console.log(`[AppStore] Extension unloaded: ${extensionId}`);
256
- return true;
257
- }
258
-
259
- function toggleExtension(extensionId: string): boolean {
260
- const extensionData = getExtension(extensionId);
261
- if (!extensionData) {
262
- return false;
263
- }
264
- extensionData.enabled = !extensionData.enabled;
265
- console.log(
266
- `[AppStore] Extension ${extensionData.enabled ? "enabled" : "disabled"}: ${extensionId}`,
267
- );
268
- return extensionData.enabled;
269
- }
129
+ const {
130
+ loadedExtensions,
131
+ extensionAPI,
132
+ setExtensionAPI,
133
+ setCodeTransformer,
134
+ getExtension,
135
+ loadExtension,
136
+ getLoadedExtensions,
137
+ unloadExtension,
138
+ toggleExtension,
139
+ setExtensionEnabled,
140
+ getExtensionEnabled,
141
+ } = useAppExtensions();
270
142
 
271
- function setExtensionEnabled(extensionId: string, enabled: boolean): boolean {
272
- const extensionData = getExtension(extensionId);
273
- if (!extensionData) {
274
- return false;
275
- }
276
- extensionData.enabled = enabled;
277
- console.log(`[AppStore] Extension ${enabled ? "enabled" : "disabled"}: ${extensionId}`);
278
- return true;
143
+ const request_counter = ref(0);
144
+ function start_request(): void {
145
+ request_counter.value += 1;
279
146
  }
280
-
281
- function getExtensionEnabled(extensionId: string): boolean {
282
- return getExtension(extensionId)?.enabled ?? false;
147
+ function stop_request(): void {
148
+ request_counter.value -= 1;
283
149
  }
150
+ const is_busy = computed(() => request_counter.value > 0);
284
151
 
285
- function upload(file: File, callbacks: RequestHandlers = {}) {
286
- const store = useAppStore();
152
+ async function upload(file: Readonly<File>, callbacks: RequestHandlers = {}): Promise<unknown> {
287
153
  const schema = opengeodeweb_front_schemas.api.local.extensions.upload;
288
154
  const { PROJECT: projectName } = useRuntimeConfig().public;
289
155
  const params = { projectName };
290
- return upload_file(
291
- store,
156
+ const result = await upload_file(
157
+ { $id: "app", base_url: base_url.value, start_request, stop_request },
292
158
  { schema, file, params },
293
159
  {
294
160
  ...callbacks,
295
161
  response_function: async (response: unknown) => {
296
- console.log("[APP] Request completed:", schema.$id);
297
162
  if (callbacks.response_function) {
298
163
  await callbacks.response_function(response);
299
164
  }
300
165
  },
301
166
  },
302
167
  );
168
+ return result;
303
169
  }
304
170
 
305
- function request(
171
+ // `TResult` is asserted, not verified, at the single `return result as TResult` boundary below: the backend response is only checked against `schema` at runtime, so callers' `TResult` is a contract with the schema, not something this function can prove.
172
+ // oxlint-disable-next-line unicorn/consistent-function-scoping
173
+ // oxlint-disable-next-line unicorn/consistent-function-scoping
174
+ async function request<TResult = unknown>(
306
175
  { schema, params }: { schema: JsonRpcSchema; params?: Record<string, unknown> },
307
176
  callbacks: RequestHandlers = {},
308
- ) {
309
- const store = useAppStore();
310
- return api_fetch(
311
- store,
177
+ ): Promise<TResult> {
178
+ const result = await api_fetch(
179
+ { $id: "app", base_url: base_url.value, start_request, stop_request },
312
180
  // The app store is only ever used with HTTP ("front") schemas, which always carry `methods`; the wider JsonRpcSchema param above is kept as-is to match this action's public signature (e.g. relayed from get_version-style callers that only know about the shared, looser schema shape).
181
+ // oxlint-disable-next-line no-unsafe-type-assertion -- narrowing optional `methods` to required is safe here; see comment above.
313
182
  { schema: schema as JsonRpcSchema & { methods: string[] }, params },
314
183
  {
315
184
  ...callbacks,
@@ -320,35 +189,29 @@ export const useAppStore = defineStore("app", () => {
320
189
  },
321
190
  },
322
191
  );
192
+ // oxlint-disable-next-line no-unsafe-type-assertion -- this is the trusted API boundary; see comment above.
193
+ return result as TResult;
323
194
  }
324
195
 
325
- const request_counter = ref(0);
326
- function start_request(): void {
327
- request_counter.value += 1;
328
- }
329
- function stop_request(): void {
330
- request_counter.value -= 1;
331
- }
332
- const is_busy = computed(() => request_counter.value > 0);
333
-
334
196
  const projectFolderPath = ref("");
335
197
 
336
- function createProjectFolder() {
198
+ async function createProjectFolder(): Promise<unknown> {
337
199
  const { PROJECT } = useRuntimeConfig().public;
338
200
  const schema = opengeodeweb_front_schemas.api.local.app.project_folder_path;
339
201
  const params = { PROJECT };
340
- return request(
202
+ const result = await request(
341
203
  { schema, params },
342
204
  {
343
205
  response_function: (response: unknown) => {
206
+ // oxlint-disable-next-line no-unsafe-type-assertion
344
207
  const { projectFolderPath: newProjectFolderPath } = response as {
345
208
  projectFolderPath: string;
346
209
  };
347
- console.log(`[APP] ${newProjectFolderPath} created`);
348
210
  projectFolderPath.value = newProjectFolderPath;
349
211
  },
350
212
  },
351
213
  );
214
+ return result;
352
215
  }
353
216
 
354
217
  return {
@@ -385,3 +248,5 @@ export const useAppStore = defineStore("app", () => {
385
248
  unregisterGlobalComponent,
386
249
  };
387
250
  });
251
+
252
+ export type { RegisterableStore };
@@ -0,0 +1,179 @@
1
+ import { killExtension } from "@ogw_front/utils/extension.js";
2
+ import { useInfraStore } from "@ogw_front/stores/infra";
3
+
4
+ import type { RegisterableStore } from "@ogw_front/stores/app";
5
+
6
+ interface ExtensionMetadata {
7
+ id: string;
8
+ store: () => RegisterableStore;
9
+ [key: string]: unknown;
10
+ }
11
+
12
+ interface ExtensionModule {
13
+ metadata: ExtensionMetadata;
14
+ install: (api: unknown, backendPath?: string) => Promise<void>;
15
+ [key: string]: unknown;
16
+ }
17
+
18
+ interface ExtensionData {
19
+ module: ExtensionModule;
20
+ id: string;
21
+ path: string;
22
+ backendPath: string | undefined;
23
+ loadedAt: string;
24
+ metadata: ExtensionMetadata;
25
+ enabled: boolean;
26
+ }
27
+
28
+ // oxlint-disable-next-line max-lines-per-function, max-statements
29
+ export function useAppExtensions(): {
30
+ loadedExtensions: typeof loadedExtensions;
31
+ extensionAPI: typeof extensionAPI;
32
+ setExtensionAPI: typeof setExtensionAPI;
33
+ setCodeTransformer: typeof setCodeTransformer;
34
+ getExtension: typeof getExtension;
35
+ loadExtension: typeof loadExtension;
36
+ getLoadedExtensions: typeof getLoadedExtensions;
37
+ unloadExtension: typeof unloadExtension;
38
+ toggleExtension: typeof toggleExtension;
39
+ setExtensionEnabled: typeof setExtensionEnabled;
40
+ getExtensionEnabled: typeof getExtensionEnabled;
41
+ } {
42
+ const loadedExtensions = ref<Map<string, ExtensionData>>(new Map());
43
+ const extensionAPI = ref<unknown>(undefined);
44
+ const codeTransformer = ref<((code: string) => string) | undefined>(undefined);
45
+
46
+ function setExtensionAPI(api: unknown): void {
47
+ extensionAPI.value = api;
48
+ }
49
+
50
+ function setCodeTransformer(transformer: (code: string) => string): void {
51
+ codeTransformer.value = transformer;
52
+ }
53
+
54
+ function getExtension(id: string): ExtensionData | undefined {
55
+ return loadedExtensions.value.get(id);
56
+ }
57
+
58
+ async function loadExtension(
59
+ path: string,
60
+ extensionPort: string,
61
+ backendPath?: string,
62
+ ): Promise<ExtensionModule> {
63
+ try {
64
+ let finalURL = path;
65
+
66
+ if (codeTransformer.value && path.startsWith("blob:")) {
67
+ const response = await fetch(path);
68
+ const code = await response.text();
69
+ const transformedCode = codeTransformer.value(code);
70
+
71
+ const newBlob = new Blob([transformedCode], {
72
+ type: "application/javascript",
73
+ });
74
+ finalURL = URL.createObjectURL(newBlob);
75
+ }
76
+ // oxlint-disable-next-line no-inline-comments, no-unsafe-assignment
77
+ const extensionModule: ExtensionModule = await import(/* @vite-ignore */ finalURL);
78
+ const store = extensionModule.metadata.store();
79
+ store.$patch?.({ default_local_port: extensionPort });
80
+
81
+ if (finalURL !== path && finalURL.startsWith("blob:")) {
82
+ URL.revokeObjectURL(finalURL);
83
+ }
84
+
85
+ if (!extensionModule.metadata?.id) {
86
+ throw new Error("Extension must have metadata.id");
87
+ }
88
+
89
+ const extensionId = extensionModule.metadata.id;
90
+
91
+ if (loadedExtensions.value.has(extensionId)) {
92
+ console.warn(`[AppStore] Extension "${extensionId}" is already loaded`);
93
+ throw new Error(`Extension "${extensionId}" is already loaded.`);
94
+ }
95
+
96
+ if (extensionAPI.value === undefined) {
97
+ throw new Error("Extension API not initialized");
98
+ }
99
+
100
+ if (typeof extensionModule.install !== "function") {
101
+ throw new TypeError("Extension must export an install function");
102
+ }
103
+
104
+ await extensionModule.install(extensionAPI.value, backendPath);
105
+
106
+ const extensionData: ExtensionData = {
107
+ module: extensionModule,
108
+ id: extensionId,
109
+ path,
110
+ backendPath,
111
+ loadedAt: new Date().toISOString(),
112
+ metadata: extensionModule.metadata,
113
+ enabled: true,
114
+ };
115
+ loadedExtensions.value.set(extensionId, extensionData);
116
+
117
+ console.log(`[AppStore] Extension loaded successfully: ${extensionId}`);
118
+ return extensionModule;
119
+ } catch (error) {
120
+ console.error(`[AppStore] Failed to load extension from ${path}:`, error);
121
+ throw error;
122
+ }
123
+ }
124
+
125
+ function getLoadedExtensions(): ExtensionData[] {
126
+ return [...loadedExtensions.value.values()];
127
+ }
128
+
129
+ async function unloadExtension(extensionId: string): Promise<boolean> {
130
+ console.log(`[AppStore] Unloading extension: ${extensionId}`);
131
+ const infraStore = useInfraStore();
132
+ infraStore.unregister_microservice(extensionId);
133
+ await killExtension(extensionId);
134
+
135
+ loadedExtensions.value.delete(extensionId);
136
+ console.log(`[AppStore] Extension unloaded: ${extensionId}`);
137
+ return true;
138
+ }
139
+
140
+ function toggleExtension(extensionId: string): boolean {
141
+ const extensionData = getExtension(extensionId);
142
+ if (!extensionData) {
143
+ return false;
144
+ }
145
+ extensionData.enabled = !extensionData.enabled;
146
+ console.log(
147
+ `[AppStore] Extension ${extensionData.enabled ? "enabled" : "disabled"}: ${extensionId}`,
148
+ );
149
+ return extensionData.enabled;
150
+ }
151
+
152
+ function setExtensionEnabled(extensionId: string, enabled: boolean): boolean {
153
+ const extensionData = getExtension(extensionId);
154
+ if (!extensionData) {
155
+ return false;
156
+ }
157
+ extensionData.enabled = enabled;
158
+ console.log(`[AppStore] Extension ${enabled ? "enabled" : "disabled"}: ${extensionId}`);
159
+ return true;
160
+ }
161
+
162
+ function getExtensionEnabled(extensionId: string): boolean {
163
+ return getExtension(extensionId)?.enabled ?? false;
164
+ }
165
+
166
+ return {
167
+ loadedExtensions,
168
+ extensionAPI,
169
+ setExtensionAPI,
170
+ setCodeTransformer,
171
+ getExtension,
172
+ loadExtension,
173
+ getLoadedExtensions,
174
+ unloadExtension,
175
+ toggleExtension,
176
+ setExtensionEnabled,
177
+ getExtensionEnabled,
178
+ };
179
+ }
@@ -42,15 +42,17 @@ export const useBackStore = defineStore("back", {
42
42
  },
43
43
  actions: {
44
44
  set_ping() {
45
+ // oxlint-disable-next-line typescript/no-floating-promises
45
46
  this.ping();
46
47
  setInterval(() => {
48
+ // oxlint-disable-next-line typescript/no-floating-promises
47
49
  this.ping();
48
50
  }, DEFAULT_PING_INTERVAL_SECONDS * MILLISECONDS_IN_SECOND);
49
51
  },
50
- ping() {
52
+ async ping() {
51
53
  const feedbackStore = useFeedbackStore();
52
54
  const schema = back_schemas.opengeodeweb_back.ping;
53
- return this.request(
55
+ const result = await this.request(
54
56
  { schema },
55
57
  {
56
58
  request_error_function: () => {
@@ -67,6 +69,7 @@ export const useBackStore = defineStore("back", {
67
69
  },
68
70
  },
69
71
  );
72
+ return result;
70
73
  },
71
74
  start_request() {
72
75
  this.request_counter += 1;
@@ -74,39 +77,43 @@ export const useBackStore = defineStore("back", {
74
77
  stop_request() {
75
78
  this.request_counter -= 1;
76
79
  },
77
- launch(args: Record<string, unknown>) {
78
- console.log("[GEODE] Launching back microservice...", { args });
80
+ async launch(args: Record<string, unknown>) {
79
81
  const appStore = useAppStore();
80
82
  const { COMMAND_BACK, NUXT_ROOT_PATH } = useRuntimeConfig().public;
81
83
  const schema = opengeodeweb_front_schemas.api.local.app.run_back;
82
84
  const params = { COMMAND_BACK, NUXT_ROOT_PATH, args };
83
85
 
84
- console.log("[GEODE] params", params);
85
- return appStore.request(
86
+ const result = await appStore.request(
86
87
  { schema, params },
87
88
  {
88
89
  response_function: (response: unknown) => {
89
- const { port } = response as { port: string };
90
- console.log(`[GEODE] Back launched on port ${port}`);
91
- this.default_local_port = port;
90
+ if (
91
+ typeof response === "object" &&
92
+ response !== null &&
93
+ "port" in response &&
94
+ (typeof response.port === "string" || typeof response.port === "number")
95
+ ) {
96
+ this.default_local_port = String(response.port);
97
+ }
92
98
  },
93
99
  },
94
100
  );
101
+ return result;
95
102
  },
96
- connect() {
97
- console.log("[GEODE] Connecting to geode microservice...");
103
+ async connect(): Promise<void> {
98
104
  this.set_ping();
99
- return Promise.resolve();
105
+ await Promise.resolve();
100
106
  },
101
- request(
107
+ async request(
102
108
  { schema, params = {} }: { schema: JsonRpcSchema; params?: Record<string, unknown> },
103
109
  callbacks: RequestHandlers = {},
104
110
  ) {
105
- return api_fetch(
111
+ const result = await api_fetch(
106
112
  this,
107
113
  // The back store is only ever used with HTTP ("front"/"back") schemas,
108
114
  // Which always carry `methods`; the wider JsonRpcSchema param above is
109
115
  // Kept as-is to match this action's public signature.
116
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion
110
117
  { schema: schema as JsonRpcSchema & { methods: string[] }, params, headers: {} },
111
118
  {
112
119
  ...callbacks,
@@ -117,10 +124,11 @@ export const useBackStore = defineStore("back", {
117
124
  },
118
125
  },
119
126
  );
127
+ return result;
120
128
  },
121
- upload(file: File, callbacks: RequestHandlers = {}) {
129
+ async upload(file: File, callbacks: RequestHandlers = {}) {
122
130
  const schema = back_schemas.opengeodeweb_back.upload_file;
123
- return upload_file(
131
+ const result = await upload_file(
124
132
  this,
125
133
  {
126
134
  schema,
@@ -135,20 +143,28 @@ export const useBackStore = defineStore("back", {
135
143
  },
136
144
  },
137
145
  );
146
+ return result;
138
147
  },
139
- get_version(schema: JsonRpcSchema | undefined) {
148
+ async get_version(schema: JsonRpcSchema | undefined) {
140
149
  if (!schema) {
141
- return;
150
+ return undefined;
142
151
  }
143
- return this.request(
152
+ const result = await this.request(
144
153
  { schema },
145
154
  {
146
155
  response_function: (response: unknown) => {
147
- const { microservice_version } = response as { microservice_version: string };
148
- this.version = microservice_version;
156
+ if (
157
+ typeof response === "object" &&
158
+ response !== null &&
159
+ "microservice_version" in response &&
160
+ typeof response.microservice_version === "string"
161
+ ) {
162
+ this.version = response.microservice_version;
163
+ }
149
164
  },
150
165
  },
151
166
  );
167
+ return result;
152
168
  },
153
169
  },
154
170
  share: {