@geode/opengeodeweb-front 10.34.0-rc.9 → 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
@@ -4,17 +4,16 @@ import { createError, defineEventHandler } from "h3";
4
4
  // Local imports
5
5
  import { getIsAppReady } from "@geode/opengeodeweb-front/server/utils/server_config.ts";
6
6
 
7
- export default defineEventHandler(async () => {
7
+ export default defineEventHandler(() => {
8
8
  try {
9
- const isReady = await getIsAppReady();
9
+ const isReady = getIsAppReady();
10
10
  console.log(`IS_APP_READY is ${isReady}`);
11
11
  return { statusCode: 200, isReady };
12
12
  } catch (error) {
13
13
  console.log(error);
14
- const err = error as { statusCode?: number; statusMessage?: string; message?: string };
15
14
  throw createError({
16
- statusCode: err.statusCode,
17
- statusMessage: err.statusMessage ?? err.message,
15
+ statusCode: 500,
16
+ statusMessage: error instanceof Error ? error.message : String(error),
18
17
  });
19
18
  }
20
19
  });
@@ -1,5 +1,5 @@
1
1
  // Third party imports
2
- import { createError, defineEventHandler, readBody } from "h3";
2
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
3
3
 
4
4
  // Local imports
5
5
  import { setAppBaseUrl } from "@geode/opengeodeweb-front/server/utils/server_config.ts";
@@ -8,23 +8,22 @@ interface SetAppBaseUrlBody {
8
8
  baseUrl: string;
9
9
  }
10
10
 
11
- export default defineEventHandler(async (event) => {
11
+ export default defineEventHandler(async (event: H3Event) => {
12
12
  try {
13
13
  const { baseUrl } = await readBody<SetAppBaseUrlBody>(event);
14
14
  if (!baseUrl) {
15
15
  throw createError({ statusCode: 400, statusMessage: "baseUrl is required" });
16
16
  }
17
17
 
18
- await setAppBaseUrl(baseUrl);
18
+ setAppBaseUrl(baseUrl);
19
19
  console.log(`Updated APP_BASE_URL to ${baseUrl}`);
20
20
 
21
21
  return { statusCode: 200, baseUrl };
22
22
  } catch (error) {
23
23
  console.log(error);
24
- const err = error as { statusCode?: number; statusMessage?: string; message?: string };
25
24
  throw createError({
26
- statusCode: err.statusCode,
27
- statusMessage: err.statusMessage ?? err.message,
25
+ statusCode: 500,
26
+ statusMessage: error instanceof Error ? error.message : String(error),
28
27
  });
29
28
  }
30
29
  });
@@ -1,5 +1,5 @@
1
1
  // Third party imports
2
- import { createError, defineEventHandler, readBody } from "h3";
2
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
3
3
 
4
4
  // Local imports
5
5
  import { setBackBaseUrl } from "@geode/opengeodeweb-front/server/utils/server_config.ts";
@@ -8,20 +8,19 @@ interface SetBackBaseUrlBody {
8
8
  baseUrl: string;
9
9
  }
10
10
 
11
- export default defineEventHandler(async (event) => {
11
+ export default defineEventHandler(async (event: H3Event) => {
12
12
  try {
13
13
  const { baseUrl } = await readBody<SetBackBaseUrlBody>(event);
14
14
  if (!baseUrl) {
15
15
  throw createError({ statusCode: 400, statusMessage: "baseUrl is required" });
16
16
  }
17
- await setBackBaseUrl(baseUrl);
17
+ setBackBaseUrl(baseUrl);
18
18
  return { statusCode: 200, baseUrl };
19
19
  } catch (error) {
20
20
  console.log(error);
21
- const err = error as { statusCode?: number; message?: string };
22
21
  throw createError({
23
- statusCode: err.statusCode,
24
- statusMessage: err.message,
22
+ statusCode: 500,
23
+ statusMessage: error instanceof Error ? error.message : String(error),
25
24
  });
26
25
  }
27
26
  });
@@ -1,5 +1,5 @@
1
1
  // Third party imports
2
- import { createError, defineEventHandler, readBody } from "h3";
2
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
3
3
 
4
4
  // Local imports
5
5
  import { setIsAppReady } from "@geode/opengeodeweb-front/server/utils/server_config.ts";
@@ -8,23 +8,22 @@ interface SetIsAppReadyBody {
8
8
  isReady: boolean;
9
9
  }
10
10
 
11
- export default defineEventHandler(async (event) => {
11
+ export default defineEventHandler(async (event: H3Event) => {
12
12
  try {
13
13
  const { isReady } = await readBody<SetIsAppReadyBody>(event);
14
14
  if (!isReady) {
15
15
  throw createError({ statusCode: 400, statusMessage: "isReady is required" });
16
16
  }
17
17
 
18
- await setIsAppReady(isReady);
18
+ setIsAppReady(isReady);
19
19
  console.log(`Updated IS_APP_READY to ${isReady}`);
20
20
 
21
21
  return { statusCode: 200, isReady };
22
22
  } catch (error) {
23
23
  console.log(error);
24
- const err = error as { statusCode?: number; statusMessage?: string; message?: string };
25
24
  throw createError({
26
- statusCode: err.statusCode,
27
- statusMessage: err.statusMessage ?? err.message,
25
+ statusCode: 500,
26
+ statusMessage: error instanceof Error ? error.message : String(error),
28
27
  });
29
28
  }
30
29
  });
@@ -1,5 +1,5 @@
1
1
  // Third party imports
2
- import { createError, defineEventHandler, readBody } from "h3";
2
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
3
3
 
4
4
  // Local imports
5
5
  import { setViewerBaseUrl } from "@geode/opengeodeweb-front/server/utils/server_config.ts";
@@ -8,20 +8,19 @@ interface SetViewerBaseUrlBody {
8
8
  baseUrl: string;
9
9
  }
10
10
 
11
- export default defineEventHandler(async (event) => {
11
+ export default defineEventHandler(async (event: H3Event) => {
12
12
  try {
13
13
  const { baseUrl } = await readBody<SetViewerBaseUrlBody>(event);
14
14
  if (!baseUrl) {
15
15
  throw createError({ statusCode: 400, statusMessage: "baseUrl is required" });
16
16
  }
17
- await setViewerBaseUrl(baseUrl);
17
+ setViewerBaseUrl(baseUrl);
18
18
  return { statusCode: 200, baseUrl };
19
19
  } catch (error) {
20
20
  console.log(error);
21
- const err = error as { statusCode?: number; message?: string };
22
21
  throw createError({
23
- statusCode: err.statusCode,
24
- statusMessage: err.message,
22
+ statusCode: 500,
23
+ statusMessage: error instanceof Error ? error.message : String(error),
25
24
  });
26
25
  }
27
26
  });
@@ -2,7 +2,7 @@
2
2
  import { promises as fs } from "node:fs";
3
3
 
4
4
  // Third party imports
5
- import { createError, defineEventHandler, readBody } from "h3";
5
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
6
6
 
7
7
  // Local imports
8
8
  import {
@@ -16,12 +16,13 @@ interface DownloadExtensionBody {
16
16
  extensionFileName: string;
17
17
  }
18
18
 
19
- export default defineEventHandler(async (event) => {
19
+ export default defineEventHandler(async (event: H3Event) => {
20
20
  try {
21
21
  const body = await readBody<DownloadExtensionBody>(event);
22
22
  const { projectName, url, extensionFileName } = body;
23
23
  console.log({ projectName, url, extensionFileName });
24
- const fileBuffer = await fetch(url).then((file) => file.arrayBuffer());
24
+ const response: Response = await fetch(url);
25
+ const fileBuffer = await response.arrayBuffer();
25
26
  const filePath = targetExtensionFilePath(projectName, extensionFileName);
26
27
  await fs.writeFile(filePath, Buffer.from(fileBuffer));
27
28
  await registerExtensionFile(projectName, filePath);
@@ -32,7 +33,7 @@ export default defineEventHandler(async (event) => {
32
33
  console.error("Error downloading extension:", error);
33
34
  throw createError({
34
35
  statusCode: 500,
35
- statusMessage: (error as Error).message,
36
+ statusMessage: error instanceof Error ? error.message : String(error),
36
37
  });
37
38
  }
38
39
  });
@@ -1,8 +1,8 @@
1
1
  // Node imports
2
2
 
3
3
  // Third party imports
4
- import { createError, defineEventHandler, readBody } from "h3";
5
- import { GoogleAuth } from "google-auth-library";
4
+ import { GoogleAuth, type JWTInput } from "google-auth-library";
5
+ import { type H3Event, createError, defineEventHandler, readBody } from "h3";
6
6
  import { ServicesClient } from "@google-cloud/run";
7
7
 
8
8
  // Local imports
@@ -12,17 +12,52 @@ interface RunCloudBody {
12
12
  email: string;
13
13
  }
14
14
 
15
- export default defineEventHandler(async (event) => {
15
+ function isServiceAccountCredentials(value: unknown): value is JWTInput {
16
+ return (
17
+ typeof value === "object" && value !== null && "client_email" in value && "private_key" in value
18
+ );
19
+ }
20
+
21
+ export default defineEventHandler(async (event: H3Event) => {
16
22
  try {
17
23
  const { email } = await readBody<RunCloudBody>(event);
18
24
  console.log("[RUN CLOUD] Received request to create backend for email:", email);
19
- const credentials = JSON.parse(process.env.GOOGLE_CLOUD_KEY as string);
25
+
26
+ const { GOOGLE_CLOUD_KEY, GOOGLE_CLOUD_PROJECT, PROJECT } = process.env;
27
+
28
+ if (
29
+ GOOGLE_CLOUD_KEY === undefined ||
30
+ GOOGLE_CLOUD_KEY === "" ||
31
+ GOOGLE_CLOUD_PROJECT === undefined ||
32
+ GOOGLE_CLOUD_PROJECT === "" ||
33
+ PROJECT === undefined ||
34
+ PROJECT === ""
35
+ ) {
36
+ throw createError({
37
+ statusCode: 500,
38
+ statusMessage:
39
+ "Missing required environment variables: GOOGLE_CLOUD_KEY, GOOGLE_CLOUD_PROJECT, or PROJECT",
40
+ });
41
+ }
42
+
43
+ const projectId: string = GOOGLE_CLOUD_PROJECT;
44
+ const projectName: string = PROJECT;
45
+
46
+ const parsedKey: unknown = JSON.parse(GOOGLE_CLOUD_KEY);
47
+ if (!isServiceAccountCredentials(parsedKey)) {
48
+ throw createError({
49
+ statusCode: 500,
50
+ statusMessage: "GOOGLE_CLOUD_KEY is not a valid service account credentials JSON",
51
+ });
52
+ }
53
+ const credentials: JWTInput = parsedKey;
54
+
20
55
  const location = "europe-west9";
21
- const projectId = process.env.GOOGLE_CLOUD_PROJECT;
22
- const projectName = process.env.PROJECT as string;
23
56
  const parent = `projects/${projectId}/locations/${location}`;
24
57
  console.log({ parent });
58
+
25
59
  const auth = new GoogleAuth({
60
+ // oxlint-disable-next-line typescript/no-deprecated
26
61
  credentials,
27
62
  scopes: ["https://www.googleapis.com/auth/cloud-platform"],
28
63
  });
@@ -30,21 +65,28 @@ export default defineEventHandler(async (event) => {
30
65
  const image = await artifactImage(parent, authClient);
31
66
  const request = requestConfig(parent, image, email, projectName);
32
67
  console.log({ request });
33
- // @google-cloud/run bundles its own copy of google-auth-library's auth-client types,
34
- // Which isn't nominally assignable to the AuthClient from our direct dependency.
35
- const runClient = new ServicesClient({ authClient: authClient as never });
68
+
69
+ const runClient = new ServicesClient({ authClient });
36
70
  const [operation] = await runClient.createService(request);
37
71
  const [response] = await operation.promise();
72
+
73
+ if (response.uri === null || response.uri === undefined || response.uri === "") {
74
+ throw createError({
75
+ statusCode: 500,
76
+ statusMessage: "Cloud Run service created but no URI was returned",
77
+ });
78
+ }
79
+
38
80
  console.log("Service URL created:", response.uri);
39
81
  return {
40
82
  statusCode: 200,
41
- url: (response.uri as string).replace(/^https?:\/\//iu, ""),
83
+ url: response.uri.replace(/^https?:\/\//iu, ""),
42
84
  };
43
85
  } catch (error) {
44
86
  console.log(error);
45
87
  throw createError({
46
88
  statusCode: 500,
47
- statusMessage: (error as Error).message,
89
+ statusMessage: error instanceof Error ? error.message : String(error),
48
90
  });
49
91
  }
50
92
  });
@@ -1,6 +1,6 @@
1
1
  // Node.js imports
2
2
  import path from "node:path";
3
- import { unlink } from "node:fs";
3
+ import { unlink } from "node:fs/promises";
4
4
 
5
5
  // Third party imports
6
6
  import Conf from "conf";
@@ -13,7 +13,7 @@ interface ExtensionsConfigSchema {
13
13
  extensions: Record<string, { path: string }>;
14
14
  }
15
15
 
16
- function projectConf(projectName: string) {
16
+ function projectConf(projectName: string): Conf<ExtensionsConfigSchema> {
17
17
  const projectConfig = new Conf<ExtensionsConfigSchema>({
18
18
  projectName,
19
19
  });
@@ -22,45 +22,42 @@ function projectConf(projectName: string) {
22
22
  });
23
23
  return projectConfig;
24
24
  }
25
- function confFolderPath(projectName: string) {
25
+
26
+ function confFolderPath(projectName: string): string {
26
27
  const projectConfig = projectConf(projectName);
27
28
  return path.dirname(projectConfig.path);
28
29
  }
29
- function targetExtensionFilePath(projectName: string, filename: string) {
30
+
31
+ function targetExtensionFilePath(projectName: string, filename: string): string {
30
32
  const safeFilename = sanitize(filename);
31
33
  const targetPath = path.join(confFolderPath(projectName), safeFilename);
32
34
  return targetPath;
33
35
  }
34
- function extensionsConf(projectName: string) {
36
+
37
+ function extensionsConf(projectName: string): ExtensionsConfigSchema["extensions"] {
35
38
  const projectConfig = projectConf(projectName);
36
- if (!projectConfig.has("extensions")) {
37
- projectConfig.set("extensions", {});
38
- }
39
- const extensionsConfig = projectConfig.get("extensions");
40
- return extensionsConfig;
39
+ // Read-only: concurrent app instances share this file and racing writes fail on Windows (EPERM)
40
+ return projectConfig.get("extensions", {});
41
41
  }
42
+
42
43
  function addExtensionToConf(
43
44
  projectName: string,
44
45
  { extensionId, extensionPath }: { extensionId: string; extensionPath: string },
45
- ) {
46
+ ): void {
46
47
  const projectConfig = projectConf(projectName);
47
48
  projectConfig.set(`extensions.${extensionId}.path`, extensionPath);
48
49
  }
49
50
 
50
51
  function extensionPathFromConf(projectName: string, extensionId: string): string {
51
52
  const projectConfig = projectConf(projectName);
52
- return projectConfig.get(`extensions.${extensionId}.path`) as string;
53
+ return projectConfig.get(`extensions.${extensionId}.path`);
53
54
  }
54
55
 
55
- async function removeExtensionFromConf(projectName: string, extensionId: string) {
56
+ async function removeExtensionFromConf(projectName: string, extensionId: string): Promise<void> {
56
57
  const projectConfig = projectConf(projectName);
57
58
  const extensionArchivePath = extensionPathFromConf(projectName, extensionId);
58
- await unlink(extensionArchivePath, (error) => {
59
- if (error) {
60
- throw error;
61
- }
62
- console.log(`${extensionArchivePath} was deleted`);
63
- });
59
+ await unlink(extensionArchivePath);
60
+ console.log(`${extensionArchivePath} was deleted`);
64
61
  projectConfig.delete(`extensions.${extensionId}`);
65
62
  console.log(`${extensionId} was deleted from ${projectName} config`);
66
63
  }
@@ -70,20 +67,30 @@ interface ExtensionMetadata {
70
67
  [key: string]: unknown;
71
68
  }
72
69
 
73
- async function registerExtensionFile(projectName: string, file: string) {
70
+ function isExtensionMetadata(value: unknown): value is ExtensionMetadata {
71
+ return (
72
+ typeof value === "object" && value !== null && "id" in value && typeof value.id === "string"
73
+ );
74
+ }
75
+
76
+ async function registerExtensionFile(projectName: string, file: string): Promise<void> {
74
77
  const StreamZipAsync = StreamZip.async;
75
78
  const zip = new StreamZipAsync({
76
79
  file,
77
80
  storeEntries: true,
78
81
  });
79
82
  const metadataJson = await zip.entryData("metadata.json");
80
- const metadata = JSON.parse(metadataJson.toString("utf8")) as ExtensionMetadata;
81
- const { id } = metadata;
83
+ const parsedMetadata: unknown = JSON.parse(metadataJson.toString("utf8"));
84
+ if (!isExtensionMetadata(parsedMetadata)) {
85
+ throw new TypeError("metadata.json does not match the expected ExtensionMetadata shape");
86
+ }
87
+ const { id } = parsedMetadata;
82
88
  addExtensionToConf(projectName, {
83
89
  extensionId: id,
84
90
  extensionPath: file,
85
91
  });
86
92
  }
93
+
87
94
  export {
88
95
  addExtensionToConf,
89
96
  confFolderPath,
@@ -1,4 +1,3 @@
1
- /// <reference path="../types/vendor.d.ts" />
2
1
  // Node imports
3
2
  import fs from "node:fs";
4
3
  import path from "node:path";
@@ -18,6 +17,7 @@ interface Microservice {
18
17
  }
19
18
 
20
19
  const MAX_DELETE_FOLDER_RETRIES = 5;
20
+
21
21
  async function deleteFolderRecursive(folderPath: string): Promise<void> {
22
22
  if (!fs.existsSync(folderPath)) {
23
23
  console.log(`Folder ${folderPath} does not exist.`);
@@ -32,7 +32,6 @@ async function deleteFolderRecursive(folderPath: string): Promise<void> {
32
32
  return;
33
33
  } catch (error) {
34
34
  console.error(`Error deleting folder ${folderPath}:`, error);
35
- // Wait before retrying
36
35
  const MILLISECONDS_PER_RETRY = 1000;
37
36
  const DELAY = MILLISECONDS_PER_RETRY * (i + 1);
38
37
  // oxlint-disable-next-line no-await-in-loop
@@ -44,35 +43,54 @@ async function deleteFolderRecursive(folderPath: string): Promise<void> {
44
43
  `Failed to delete folder ${folderPath} after ${MAX_DELETE_FOLDER_RETRIES} retries`,
45
44
  );
46
45
  }
47
- function killHttpMicroservice(microservice: Microservice): Promise<void> {
46
+
47
+ function isErrorWithMessage(error: unknown): error is { message: string } {
48
+ return (
49
+ typeof error === "object" &&
50
+ error !== null &&
51
+ "message" in error &&
52
+ typeof error.message === "string"
53
+ );
54
+ }
55
+
56
+ async function killHttpMicroservice(microservice: Microservice): Promise<void> {
48
57
  console.log("killHttpMicroservice", {
49
58
  ...microservice,
50
59
  });
51
60
  const failMessage = `Failed to kill ${microservice.name}`;
52
- async function do_kill() {
61
+ async function do_kill(): Promise<void> {
62
+ if (microservice.url === undefined) {
63
+ return;
64
+ }
53
65
  try {
54
- await fetch(microservice.url as string, {
66
+ await fetch(microservice.url, {
55
67
  method: microservice.method,
56
68
  });
57
69
  } catch (error) {
58
- console.log(`Expected error during kill of ${microservice.name}:`, (error as Error).message);
70
+ const message = isErrorWithMessage(error) ? error.message : String(error);
71
+ console.log(`Expected error during kill of ${microservice.name}:`, message);
59
72
  }
60
73
  }
61
- return pTimeout(do_kill(), {
74
+ await pTimeout(do_kill(), {
62
75
  milliseconds: 5000,
63
76
  message: failMessage,
64
77
  });
65
78
  }
66
- function killWebsocketMicroservice(microservice: Microservice): Promise<void> {
79
+
80
+ async function killWebsocketMicroservice(microservice: Microservice): Promise<void> {
67
81
  console.log("killWebsocketMicroservice", {
68
82
  ...microservice,
69
83
  });
70
84
  const failMessage = `Failed to kill ${microservice.name}`;
71
85
  const successMessage = `Disconnected from ${microservice.name} WebSocket server`;
72
- function do_kill() {
86
+ async function do_kill(): Promise<void> {
87
+ if (microservice.url === undefined) {
88
+ return;
89
+ }
90
+ const socketUrl = microservice.url;
73
91
  // oxlint-disable-next-line promise/avoid-new
74
- return new Promise<void>((resolve) => {
75
- const socket = new WebSocket(microservice.url as string);
92
+ await new Promise<void>((resolve) => {
93
+ const socket = new WebSocket(socketUrl);
76
94
  socket.on("open", () => {
77
95
  console.log("Connected to WebSocket server");
78
96
  socket.send(
@@ -87,7 +105,7 @@ function killWebsocketMicroservice(microservice: Microservice): Promise<void> {
87
105
  }),
88
106
  );
89
107
  });
90
- socket.on("message", (data) => {
108
+ socket.on("message", (data: Buffer | string) => {
91
109
  const message = data.toString();
92
110
  console.log("Received from server:", message);
93
111
  if (message.includes("hello")) {
@@ -106,46 +124,54 @@ function killWebsocketMicroservice(microservice: Microservice): Promise<void> {
106
124
  console.log(successMessage);
107
125
  resolve();
108
126
  });
109
- socket.on("error", (error) => {
127
+ socket.on("error", (error: Error) => {
110
128
  console.error("WebSocket error:", error);
111
129
  socket.close();
112
130
  resolve();
113
131
  });
114
132
  });
115
133
  }
116
- return pTimeout(do_kill(), {
134
+ await pTimeout(do_kill(), {
117
135
  milliseconds: 5000,
118
136
  message: failMessage,
119
137
  });
120
138
  }
139
+
121
140
  async function killMicroservice(microservice: Microservice): Promise<void> {
122
141
  if (microservice.type === "back") {
123
142
  await killHttpMicroservice(microservice);
124
143
  } else if (microservice.type === "viewer") {
125
144
  await killWebsocketMicroservice(microservice);
126
145
  } else {
127
- throw new Error(`Unknown microservice type: ${microservice.type}`);
146
+ const exhaustiveCheck: never = microservice.type;
147
+ throw new Error(`Unknown microservice type: ${String(exhaustiveCheck)}`);
128
148
  }
129
149
  }
130
- async function killMicroservices(microservices: Microservice[]): Promise<void> {
150
+
151
+ async function killMicroservices(microservices: readonly Microservice[]): Promise<Microservice[]> {
131
152
  console.log("killMicroservices", {
132
153
  microservices,
133
154
  });
134
155
  const results = await Promise.allSettled(
135
- microservices.map((microservice) => killMicroservice(microservice)),
156
+ microservices.map(async (microservice) => {
157
+ await killMicroservice(microservice);
158
+ }),
136
159
  );
137
- const killed = microservices.filter((_, index) => results[index]?.status === "fulfilled");
138
- for (let i = 0; i < killed.length; i += 1) {
139
- const microservice = microservices[i];
140
- if (microservice) {
141
- microservices.splice(microservices.indexOf(microservice), 1);
142
- }
143
- }
160
+ return microservices.filter((_, index) => results[index]?.status !== "fulfilled");
144
161
  }
162
+
145
163
  function microservicesMetadatasPath(projectFolderPath: string): string {
146
164
  return path.join(projectFolderPath, "microservices.json");
147
165
  }
148
166
 
167
+ function isMicroservicesMetadatas(value: unknown): value is { microservices: Microservice[] } {
168
+ return (
169
+ typeof value === "object" &&
170
+ value !== null &&
171
+ Array.isArray((value as { microservices?: unknown }).microservices)
172
+ );
173
+ }
174
+
149
175
  function projectMicroservices(projectFolderPath: string): Microservice[] {
150
176
  console.log("projectMicroservices", {
151
177
  projectFolderPath,
@@ -157,11 +183,13 @@ function projectMicroservices(projectFolderPath: string): Microservice[] {
157
183
  };
158
184
  fs.writeFileSync(filePath, JSON.stringify(microservicesMetadatas, undefined, 2), "utf8");
159
185
  }
160
- const content = JSON.parse(fs.readFileSync(filePath, "utf8")) as {
161
- microservices: Microservice[];
162
- };
163
- return content.microservices;
186
+ const parsed: unknown = JSON.parse(fs.readFileSync(filePath, "utf8"));
187
+ if (!isMicroservicesMetadatas(parsed)) {
188
+ throw new Error(`Invalid microservices metadata file: ${filePath}`);
189
+ }
190
+ return parsed.microservices;
164
191
  }
192
+
165
193
  async function cleanupBackend(projectFolderPath: string): Promise<void> {
166
194
  if (!fs.existsSync(projectFolderPath)) {
167
195
  console.log(`Folder ${projectFolderPath} does not exist. Skipping cleanup.`);
@@ -171,11 +199,13 @@ async function cleanupBackend(projectFolderPath: string): Promise<void> {
171
199
  await killMicroservices(microservices);
172
200
  await deleteFolderRecursive(projectFolderPath);
173
201
  }
202
+
174
203
  function getMicroserviceByName(
175
- microservices: Microservice[],
204
+ microservices: readonly Microservice[],
176
205
  name: string,
177
206
  ): Microservice | undefined {
178
- return microservices.find((microservice) => microservice.name === name);
207
+ const found = microservices.find((microservice) => microservice.name === name);
208
+ return found === undefined ? undefined : { ...found };
179
209
  }
180
210
 
181
211
  export {
@@ -4,25 +4,23 @@ import fs from "node:fs";
4
4
  import path from "node:path";
5
5
 
6
6
  // Third party imports
7
+ import type { AuthClient, OAuth2Client } from "google-auth-library";
7
8
  import { google } from "googleapis";
8
9
  import type { protos } from "@google-cloud/run";
9
10
 
10
11
  // Local imports
11
12
 
12
- // The googleapis package's per-API-version `auth` option types don't line up with the concrete client returned by `GoogleAuth.getClient()` (they're structurally close but not nominally assignable). `any` matches how googleapis treats it at runtime (duck typed).
13
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
- type GoogleAuthClient = any;
15
- // `v2` is a namespace segment in the `@google-cloud/run` package's own generated protobuf types, not a name this codebase declares.
16
13
  // oxlint-disable-next-line eslint/id-length
17
14
  type CreateServiceRequest = protos.google.cloud.run.v2.ICreateServiceRequest;
18
15
 
19
16
  const LOCATIONS_DIR = "/etc/nginx/locations";
20
17
 
21
- async function artifactImage(parent: string, authClient: GoogleAuthClient): Promise<string> {
18
+ async function artifactImage(parent: string, authClient: AuthClient): Promise<string> {
22
19
  const projectName = process.env.PROJECT;
23
20
  const registry = google.artifactregistry({
24
21
  version: "v1",
25
- auth: authClient,
22
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion
23
+ auth: authClient as OAuth2Client,
26
24
  });
27
25
  const branch = process.env.NETLIFY_BRANCH;
28
26
  const [, projectId] = parent.split("/");
@@ -86,7 +84,6 @@ function requestConfig(
86
84
  image,
87
85
  ports: [
88
86
  {
89
- name: "h2c",
90
87
  containerPort: 80,
91
88
  },
92
89
  ],
@@ -112,7 +109,11 @@ function requestConfig(
112
109
  };
113
110
  }
114
111
 
115
- function addSupervisorProgram(name: string, command: string, executableArgs: string[]): void {
112
+ function addSupervisorProgram(
113
+ name: string,
114
+ command: string,
115
+ executableArgs: readonly string[],
116
+ ): void {
116
117
  const conf = `
117
118
  [program:${name}]
118
119
  command=${command} ${executableArgs.join(" ")}